合并6.8.0代码
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
package com.opensource.svgaplayer.drawer
|
||||
|
||||
import android.graphics.Canvas
|
||||
import android.widget.ImageView
|
||||
import com.opensource.svgaplayer.SVGAVideoEntity
|
||||
import com.opensource.svgaplayer.entities.SVGAVideoSpriteFrameEntity
|
||||
import com.opensource.svgaplayer.utils.Pools
|
||||
import com.opensource.svgaplayer.utils.SVGAScaleInfo
|
||||
import kotlin.math.max
|
||||
|
||||
/**
|
||||
* Created by cuiminghui on 2017/3/29.
|
||||
*/
|
||||
|
||||
open internal class SGVADrawer(val videoItem: SVGAVideoEntity) {
|
||||
|
||||
val scaleInfo = SVGAScaleInfo()
|
||||
|
||||
private val spritePool = Pools.SimplePool<SVGADrawerSprite>(max(1, videoItem.spriteList.size))
|
||||
|
||||
inner class SVGADrawerSprite(var _matteKey: String? = null, var _imageKey: String? = null, var _frameEntity: SVGAVideoSpriteFrameEntity? = null) {
|
||||
val matteKey get() = _matteKey
|
||||
val imageKey get() = _imageKey
|
||||
val frameEntity get() = _frameEntity!!
|
||||
}
|
||||
|
||||
internal fun requestFrameSprites(frameIndex: Int): List<SVGADrawerSprite> {
|
||||
return videoItem.spriteList.mapNotNull {
|
||||
if (frameIndex >= 0 && frameIndex < it.frames.size) {
|
||||
it.imageKey?.let { imageKey ->
|
||||
if (!imageKey.endsWith(".matte") && it.frames[frameIndex].alpha <= 0.0) {
|
||||
return@mapNotNull null
|
||||
}
|
||||
return@mapNotNull (spritePool.acquire() ?: SVGADrawerSprite()).apply {
|
||||
_matteKey = it.matteKey
|
||||
_imageKey = it.imageKey
|
||||
_frameEntity = it.frames[frameIndex]
|
||||
}
|
||||
}
|
||||
}
|
||||
return@mapNotNull null
|
||||
}
|
||||
}
|
||||
|
||||
internal fun releaseFrameSprites(sprites: List<SVGADrawerSprite>) {
|
||||
sprites.forEach { spritePool.release(it) }
|
||||
}
|
||||
|
||||
open fun drawFrame(canvas : Canvas, frameIndex: Int, scaleType: ImageView.ScaleType) {
|
||||
scaleInfo.performScaleType(canvas.width.toFloat(),canvas.height.toFloat(), videoItem.videoSize.width.toFloat(), videoItem.videoSize.height.toFloat(), scaleType)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,559 @@
|
||||
package com.opensource.svgaplayer.drawer
|
||||
|
||||
import android.graphics.*
|
||||
import android.os.Build
|
||||
import android.text.StaticLayout
|
||||
import android.text.TextUtils
|
||||
import android.widget.ImageView
|
||||
import com.opensource.svgaplayer.SVGADynamicEntity
|
||||
import com.opensource.svgaplayer.SVGASoundManager
|
||||
import com.opensource.svgaplayer.SVGAVideoEntity
|
||||
import com.opensource.svgaplayer.entities.SVGAVideoShapeEntity
|
||||
|
||||
/**
|
||||
* Created by cuiminghui on 2017/3/29.
|
||||
*/
|
||||
|
||||
internal class SVGACanvasDrawer(videoItem: SVGAVideoEntity, val dynamicItem: SVGADynamicEntity) : SGVADrawer(videoItem) {
|
||||
|
||||
private val sharedValues = ShareValues()
|
||||
private val drawTextCache: HashMap<String, Bitmap> = hashMapOf()
|
||||
private val pathCache = PathCache()
|
||||
|
||||
private var beginIndexList: Array<Boolean>? = null
|
||||
private var endIndexList: Array<Boolean>? = null
|
||||
|
||||
override fun drawFrame(canvas: Canvas, frameIndex: Int, scaleType: ImageView.ScaleType) {
|
||||
super.drawFrame(canvas, frameIndex, scaleType)
|
||||
playAudio(frameIndex)
|
||||
this.pathCache.onSizeChanged(canvas)
|
||||
val sprites = requestFrameSprites(frameIndex)
|
||||
// Filter null sprites
|
||||
if (sprites.count() <= 0) return
|
||||
val matteSprites = mutableMapOf<String, SVGADrawerSprite>()
|
||||
var saveID = -1
|
||||
beginIndexList = null
|
||||
endIndexList = null
|
||||
|
||||
// Filter no matte layer
|
||||
var hasMatteLayer = false
|
||||
sprites.get(0).imageKey?.let {
|
||||
if (it.endsWith(".matte")) {
|
||||
hasMatteLayer = true
|
||||
}
|
||||
}
|
||||
sprites.forEachIndexed { index, svgaDrawerSprite ->
|
||||
|
||||
// Save matte sprite
|
||||
svgaDrawerSprite.imageKey?.let {
|
||||
/// No matte layer included or VERSION Unsopport matte
|
||||
if (!hasMatteLayer || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
// Normal sprite
|
||||
drawSprite(svgaDrawerSprite, canvas, frameIndex)
|
||||
// Continue
|
||||
return@forEachIndexed
|
||||
}
|
||||
/// Cache matte sprite
|
||||
if (it.endsWith(".matte")) {
|
||||
matteSprites.put(it, svgaDrawerSprite)
|
||||
// Continue
|
||||
return@forEachIndexed
|
||||
}
|
||||
}
|
||||
/// Is matte begin
|
||||
if (isMatteBegin(index, sprites)) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
saveID = canvas.saveLayer(0f, 0f, canvas.width.toFloat(), canvas.height.toFloat(), null)
|
||||
} else {
|
||||
canvas.save()
|
||||
}
|
||||
}
|
||||
/// Normal matte
|
||||
drawSprite(svgaDrawerSprite, canvas, frameIndex)
|
||||
|
||||
/// Is matte end
|
||||
if (isMatteEnd(index, sprites)) {
|
||||
matteSprites.get(svgaDrawerSprite.matteKey)?.let {
|
||||
drawSprite(it, this.sharedValues.shareMatteCanvas(canvas.width, canvas.height), frameIndex)
|
||||
canvas.drawBitmap(this.sharedValues.sharedMatteBitmap(), 0f, 0f, this.sharedValues.shareMattePaint())
|
||||
if (saveID != -1) {
|
||||
canvas.restoreToCount(saveID)
|
||||
} else {
|
||||
canvas.restore()
|
||||
}
|
||||
// Continue
|
||||
return@forEachIndexed
|
||||
}
|
||||
}
|
||||
}
|
||||
releaseFrameSprites(sprites)
|
||||
}
|
||||
|
||||
private fun isMatteBegin(spriteIndex: Int, sprites: List<SVGADrawerSprite>): Boolean {
|
||||
if (beginIndexList == null) {
|
||||
val boolArray = Array(sprites.count()) { false }
|
||||
sprites.forEachIndexed { index, svgaDrawerSprite ->
|
||||
svgaDrawerSprite.imageKey?.let {
|
||||
/// Filter matte sprite
|
||||
if (it.endsWith(".matte")) {
|
||||
// Continue
|
||||
return@forEachIndexed
|
||||
}
|
||||
}
|
||||
svgaDrawerSprite.matteKey?.let {
|
||||
if (it.length > 0) {
|
||||
sprites.get(index - 1)?.let { lastSprite ->
|
||||
if (lastSprite.matteKey.isNullOrEmpty()) {
|
||||
boolArray[index] = true
|
||||
} else {
|
||||
if (lastSprite.matteKey != svgaDrawerSprite.matteKey) {
|
||||
boolArray[index] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
beginIndexList = boolArray
|
||||
}
|
||||
return beginIndexList?.get(spriteIndex) ?: false
|
||||
}
|
||||
|
||||
private fun isMatteEnd(spriteIndex: Int, sprites: List<SVGADrawerSprite>): Boolean {
|
||||
if (endIndexList == null) {
|
||||
val boolArray = Array(sprites.count()) { false }
|
||||
sprites.forEachIndexed { index, svgaDrawerSprite ->
|
||||
svgaDrawerSprite.imageKey?.let {
|
||||
/// Filter matte sprite
|
||||
if (it.endsWith(".matte")) {
|
||||
// Continue
|
||||
return@forEachIndexed
|
||||
}
|
||||
}
|
||||
svgaDrawerSprite.matteKey?.let {
|
||||
if (it.length > 0) {
|
||||
// Last one
|
||||
if (index == sprites.count() - 1) {
|
||||
boolArray[index] = true
|
||||
} else {
|
||||
sprites.get(index + 1)?.let { nextSprite ->
|
||||
if (nextSprite.matteKey.isNullOrEmpty()) {
|
||||
boolArray[index] = true
|
||||
} else {
|
||||
if (nextSprite.matteKey != svgaDrawerSprite.matteKey) {
|
||||
boolArray[index] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
endIndexList = boolArray
|
||||
}
|
||||
return endIndexList?.get(spriteIndex) ?: false
|
||||
}
|
||||
|
||||
private fun playAudio(frameIndex: Int) {
|
||||
this.videoItem.audioList.forEach { audio ->
|
||||
if (audio.startFrame == frameIndex) {
|
||||
if (SVGASoundManager.isInit()) {
|
||||
audio.soundID?.let { soundID ->
|
||||
audio.playID = SVGASoundManager.play(soundID)
|
||||
}
|
||||
} else {
|
||||
this.videoItem.soundPool?.let { soundPool ->
|
||||
audio.soundID?.let { soundID ->
|
||||
audio.playID = soundPool.play(soundID, 1.0f, 1.0f, 1, 0, 1.0f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (audio.endFrame <= frameIndex) {
|
||||
audio.playID?.let {
|
||||
if (SVGASoundManager.isInit()) {
|
||||
SVGASoundManager.stop(it)
|
||||
} else {
|
||||
this.videoItem.soundPool?.stop(it)
|
||||
}
|
||||
}
|
||||
audio.playID = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun shareFrameMatrix(transform: Matrix): Matrix {
|
||||
val matrix = this.sharedValues.sharedMatrix()
|
||||
matrix.postScale(scaleInfo.scaleFx, scaleInfo.scaleFy)
|
||||
matrix.postTranslate(scaleInfo.tranFx, scaleInfo.tranFy)
|
||||
matrix.preConcat(transform)
|
||||
return matrix
|
||||
}
|
||||
|
||||
private fun drawSprite(sprite: SVGADrawerSprite, canvas: Canvas, frameIndex: Int) {
|
||||
drawImage(sprite, canvas)
|
||||
drawShape(sprite, canvas)
|
||||
drawDynamic(sprite, canvas, frameIndex)
|
||||
}
|
||||
|
||||
private fun drawImage(sprite: SVGADrawerSprite, canvas: Canvas) {
|
||||
val imageKey = sprite.imageKey ?: return
|
||||
val isHidden = dynamicItem.dynamicHidden[imageKey] == true
|
||||
if (isHidden) {
|
||||
return
|
||||
}
|
||||
val bitmapKey = if (imageKey.endsWith(".matte")) imageKey.substring(0, imageKey.length - 6) else imageKey
|
||||
val drawingBitmap = (dynamicItem.dynamicImage[bitmapKey] ?: videoItem.imageMap[bitmapKey])
|
||||
?: return
|
||||
val frameMatrix = shareFrameMatrix(sprite.frameEntity.transform)
|
||||
val paint = this.sharedValues.sharedPaint()
|
||||
paint.isAntiAlias = videoItem.antiAlias
|
||||
paint.isFilterBitmap = videoItem.antiAlias
|
||||
paint.alpha = (sprite.frameEntity.alpha * 255).toInt()
|
||||
if (sprite.frameEntity.maskPath != null) {
|
||||
val maskPath = sprite.frameEntity.maskPath ?: return
|
||||
canvas.save()
|
||||
val path = this.sharedValues.sharedPath()
|
||||
maskPath.buildPath(path)
|
||||
path.transform(frameMatrix)
|
||||
canvas.clipPath(path)
|
||||
frameMatrix.preScale((sprite.frameEntity.layout.width / drawingBitmap.width).toFloat(), (sprite.frameEntity.layout.height / drawingBitmap.height).toFloat())
|
||||
if (!drawingBitmap.isRecycled) {
|
||||
canvas.drawBitmap(drawingBitmap, frameMatrix, paint)
|
||||
}
|
||||
canvas.restore()
|
||||
} else {
|
||||
frameMatrix.preScale((sprite.frameEntity.layout.width / drawingBitmap.width).toFloat(), (sprite.frameEntity.layout.height / drawingBitmap.height).toFloat())
|
||||
if (!drawingBitmap.isRecycled) {
|
||||
canvas.drawBitmap(drawingBitmap, frameMatrix, paint)
|
||||
}
|
||||
}
|
||||
dynamicItem.dynamicIClickArea.let {
|
||||
it.get(imageKey)?.let { listener ->
|
||||
val matrixArray = floatArrayOf(0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f)
|
||||
frameMatrix.getValues(matrixArray)
|
||||
listener.onResponseArea(imageKey, matrixArray[2].toInt()
|
||||
, matrixArray[5].toInt()
|
||||
, (drawingBitmap.width * matrixArray[0] + matrixArray[2]).toInt()
|
||||
, (drawingBitmap.height * matrixArray[4] + matrixArray[5]).toInt())
|
||||
}
|
||||
}
|
||||
drawTextOnBitmap(canvas, drawingBitmap, sprite, frameMatrix)
|
||||
}
|
||||
|
||||
private fun drawTextOnBitmap(canvas: Canvas, drawingBitmap: Bitmap, sprite: SVGADrawerSprite, frameMatrix: Matrix) {
|
||||
if (dynamicItem.isTextDirty) {
|
||||
this.drawTextCache.clear()
|
||||
dynamicItem.isTextDirty = false
|
||||
}
|
||||
val imageKey = sprite.imageKey ?: return
|
||||
var textBitmap: Bitmap? = null
|
||||
dynamicItem.dynamicText[imageKey]?.let { drawingText ->
|
||||
dynamicItem.dynamicTextPaint[imageKey]?.let { drawingTextPaint ->
|
||||
drawTextCache[imageKey]?.let {
|
||||
textBitmap = it
|
||||
} ?: kotlin.run {
|
||||
textBitmap = Bitmap.createBitmap(drawingBitmap.width, drawingBitmap.height, Bitmap.Config.ARGB_8888)
|
||||
val drawRect = Rect(0, 0, drawingBitmap.width, drawingBitmap.height)
|
||||
val textCanvas = Canvas(textBitmap)
|
||||
drawingTextPaint.isAntiAlias = true
|
||||
val fontMetrics = drawingTextPaint.getFontMetrics();
|
||||
val top = fontMetrics.top
|
||||
val bottom = fontMetrics.bottom
|
||||
val baseLineY = drawRect.centerY() - top / 2 - bottom / 2
|
||||
textCanvas.drawText(drawingText, drawRect.centerX().toFloat(), baseLineY, drawingTextPaint);
|
||||
drawTextCache.put(imageKey, textBitmap as Bitmap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dynamicItem.dynamicBoringLayoutText[imageKey]?.let {
|
||||
drawTextCache[imageKey]?.let {
|
||||
textBitmap = it
|
||||
} ?: kotlin.run {
|
||||
it.paint.isAntiAlias = true
|
||||
|
||||
textBitmap = Bitmap.createBitmap(drawingBitmap.width, drawingBitmap.height, Bitmap.Config.ARGB_8888)
|
||||
val textCanvas = Canvas(textBitmap)
|
||||
textCanvas.translate(0f, ((drawingBitmap.height - it.height) / 2).toFloat())
|
||||
it.draw(textCanvas)
|
||||
drawTextCache.put(imageKey, textBitmap as Bitmap)
|
||||
}
|
||||
}
|
||||
|
||||
dynamicItem.dynamicStaticLayoutText[imageKey]?.let {
|
||||
drawTextCache[imageKey]?.let {
|
||||
textBitmap = it
|
||||
} ?: kotlin.run {
|
||||
it.paint.isAntiAlias = true
|
||||
var layout = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
var lineMax = try {
|
||||
val field = StaticLayout::class.java.getDeclaredField("mMaximumVisibleLineCount")
|
||||
field.isAccessible = true
|
||||
field.getInt(it)
|
||||
} catch (e: Exception) {
|
||||
Int.MAX_VALUE
|
||||
}
|
||||
StaticLayout.Builder
|
||||
.obtain(it.text, 0, it.text.length, it.paint, drawingBitmap.width)
|
||||
.setAlignment(it.alignment)
|
||||
.setMaxLines(lineMax)
|
||||
.setEllipsize(TextUtils.TruncateAt.END)
|
||||
.build()
|
||||
} else {
|
||||
StaticLayout(it.text, 0, it.text.length, it.paint, drawingBitmap.width, it.alignment, it.spacingMultiplier, it.spacingAdd, false)
|
||||
}
|
||||
textBitmap = Bitmap.createBitmap(drawingBitmap.width, drawingBitmap.height, Bitmap.Config.ARGB_8888)
|
||||
val textCanvas = Canvas(textBitmap)
|
||||
textCanvas.translate(0f, ((drawingBitmap.height - layout.height) / 2).toFloat())
|
||||
layout.draw(textCanvas)
|
||||
drawTextCache.put(imageKey, textBitmap as Bitmap)
|
||||
}
|
||||
}
|
||||
textBitmap?.let { textBitmap ->
|
||||
val paint = this.sharedValues.sharedPaint()
|
||||
paint.isAntiAlias = videoItem.antiAlias
|
||||
paint.alpha = (sprite.frameEntity.alpha * 255).toInt()
|
||||
if (sprite.frameEntity.maskPath != null) {
|
||||
val maskPath = sprite.frameEntity.maskPath ?: return@let
|
||||
canvas.save()
|
||||
canvas.concat(frameMatrix)
|
||||
canvas.clipRect(0, 0, drawingBitmap.width, drawingBitmap.height)
|
||||
val bitmapShader = BitmapShader(textBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT)
|
||||
paint.shader = bitmapShader
|
||||
val path = this.sharedValues.sharedPath()
|
||||
maskPath.buildPath(path)
|
||||
canvas.drawPath(path, paint)
|
||||
canvas.restore()
|
||||
} else {
|
||||
paint.isFilterBitmap = videoItem.antiAlias
|
||||
canvas.drawBitmap(textBitmap, frameMatrix, paint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun drawShape(sprite: SVGADrawerSprite, canvas: Canvas) {
|
||||
val frameMatrix = shareFrameMatrix(sprite.frameEntity.transform)
|
||||
sprite.frameEntity.shapes.forEach { shape ->
|
||||
shape.buildPath()
|
||||
shape.shapePath?.let {
|
||||
val paint = this.sharedValues.sharedPaint()
|
||||
paint.reset()
|
||||
paint.isAntiAlias = videoItem.antiAlias
|
||||
paint.alpha = (sprite.frameEntity.alpha * 255).toInt()
|
||||
val path = this.sharedValues.sharedPath()
|
||||
path.reset()
|
||||
path.addPath(this.pathCache.buildPath(shape))
|
||||
val shapeMatrix = this.sharedValues.sharedMatrix2()
|
||||
shapeMatrix.reset()
|
||||
shape.transform?.let {
|
||||
shapeMatrix.postConcat(it)
|
||||
}
|
||||
shapeMatrix.postConcat(frameMatrix)
|
||||
path.transform(shapeMatrix)
|
||||
shape.styles?.fill?.let {
|
||||
if (it != 0x00000000) {
|
||||
paint.style = Paint.Style.FILL
|
||||
paint.color = it
|
||||
val alpha = Math.min(255, Math.max(0, (sprite.frameEntity.alpha * 255).toInt()))
|
||||
if (alpha != 255) {
|
||||
paint.alpha = alpha
|
||||
}
|
||||
if (sprite.frameEntity.maskPath !== null) canvas.save()
|
||||
sprite.frameEntity.maskPath?.let { maskPath ->
|
||||
val path2 = this.sharedValues.sharedPath2()
|
||||
maskPath.buildPath(path2)
|
||||
path2.transform(frameMatrix)
|
||||
canvas.clipPath(path2)
|
||||
}
|
||||
canvas.drawPath(path, paint)
|
||||
if (sprite.frameEntity.maskPath !== null) canvas.restore()
|
||||
}
|
||||
}
|
||||
shape.styles?.strokeWidth?.let {
|
||||
if (it > 0) {
|
||||
paint.alpha = (sprite.frameEntity.alpha * 255).toInt()
|
||||
paint.style = Paint.Style.STROKE
|
||||
shape.styles?.stroke?.let {
|
||||
paint.color = it
|
||||
val alpha = Math.min(255, Math.max(0, (sprite.frameEntity.alpha * 255).toInt()))
|
||||
if (alpha != 255) {
|
||||
paint.alpha = alpha
|
||||
}
|
||||
}
|
||||
val scale = matrixScale(frameMatrix)
|
||||
shape.styles?.strokeWidth?.let {
|
||||
paint.strokeWidth = it * scale
|
||||
}
|
||||
shape.styles?.lineCap?.let {
|
||||
when {
|
||||
it.equals("butt", true) -> paint.strokeCap = Paint.Cap.BUTT
|
||||
it.equals("round", true) -> paint.strokeCap = Paint.Cap.ROUND
|
||||
it.equals("square", true) -> paint.strokeCap = Paint.Cap.SQUARE
|
||||
}
|
||||
}
|
||||
shape.styles?.lineJoin?.let {
|
||||
when {
|
||||
it.equals("miter", true) -> paint.strokeJoin = Paint.Join.MITER
|
||||
it.equals("round", true) -> paint.strokeJoin = Paint.Join.ROUND
|
||||
it.equals("bevel", true) -> paint.strokeJoin = Paint.Join.BEVEL
|
||||
}
|
||||
}
|
||||
shape.styles?.miterLimit?.let {
|
||||
paint.strokeMiter = it.toFloat() * scale
|
||||
}
|
||||
shape.styles?.lineDash?.let {
|
||||
if (it.size == 3 && (it[0] > 0 || it[1] > 0)) {
|
||||
paint.pathEffect = DashPathEffect(floatArrayOf(
|
||||
(if (it[0] < 1.0f) 1.0f else it[0]) * scale,
|
||||
(if (it[1] < 0.1f) 0.1f else it[1]) * scale
|
||||
), it[2] * scale)
|
||||
}
|
||||
}
|
||||
if (sprite.frameEntity.maskPath !== null) canvas.save()
|
||||
sprite.frameEntity.maskPath?.let { maskPath ->
|
||||
val path2 = this.sharedValues.sharedPath2()
|
||||
maskPath.buildPath(path2)
|
||||
path2.transform(frameMatrix)
|
||||
canvas.clipPath(path2)
|
||||
}
|
||||
canvas.drawPath(path, paint)
|
||||
if (sprite.frameEntity.maskPath !== null) canvas.restore()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private val matrixScaleTempValues = FloatArray(16)
|
||||
|
||||
private fun matrixScale(matrix: Matrix): Float {
|
||||
matrix.getValues(matrixScaleTempValues)
|
||||
if (matrixScaleTempValues[0] == 0f) {
|
||||
return 0f
|
||||
}
|
||||
var A = matrixScaleTempValues[0].toDouble()
|
||||
var B = matrixScaleTempValues[3].toDouble()
|
||||
var C = matrixScaleTempValues[1].toDouble()
|
||||
var D = matrixScaleTempValues[4].toDouble()
|
||||
if (A * D == B * C) return 0f
|
||||
var scaleX = Math.sqrt(A * A + B * B)
|
||||
A /= scaleX
|
||||
B /= scaleX
|
||||
var skew = A * C + B * D
|
||||
C -= A * skew
|
||||
D -= B * skew
|
||||
var scaleY = Math.sqrt(C * C + D * D)
|
||||
C /= scaleY
|
||||
D /= scaleY
|
||||
skew /= scaleY
|
||||
if (A * D < B * C) {
|
||||
scaleX = -scaleX
|
||||
}
|
||||
return if (scaleInfo.ratioX) Math.abs(scaleX.toFloat()) else Math.abs(scaleY.toFloat())
|
||||
}
|
||||
|
||||
private fun drawDynamic(sprite: SVGADrawerSprite, canvas: Canvas, frameIndex: Int) {
|
||||
val imageKey = sprite.imageKey ?: return
|
||||
dynamicItem.dynamicDrawer[imageKey]?.let {
|
||||
val frameMatrix = shareFrameMatrix(sprite.frameEntity.transform)
|
||||
canvas.save()
|
||||
canvas.concat(frameMatrix)
|
||||
it.invoke(canvas, frameIndex)
|
||||
canvas.restore()
|
||||
}
|
||||
dynamicItem.dynamicDrawerSized[imageKey]?.let {
|
||||
val frameMatrix = shareFrameMatrix(sprite.frameEntity.transform)
|
||||
canvas.save()
|
||||
canvas.concat(frameMatrix)
|
||||
it.invoke(canvas, frameIndex, sprite.frameEntity.layout.width.toInt(), sprite.frameEntity.layout.height.toInt())
|
||||
canvas.restore()
|
||||
}
|
||||
}
|
||||
|
||||
class ShareValues {
|
||||
|
||||
private val sharedPaint = Paint()
|
||||
private val sharedPath = Path()
|
||||
private val sharedPath2 = Path()
|
||||
private val sharedMatrix = Matrix()
|
||||
private val sharedMatrix2 = Matrix()
|
||||
|
||||
private val shareMattePaint = Paint()
|
||||
private var shareMatteCanvas: Canvas? = null
|
||||
private var sharedMatteBitmap: Bitmap? = null
|
||||
|
||||
fun sharedPaint(): Paint {
|
||||
sharedPaint.reset()
|
||||
return sharedPaint
|
||||
}
|
||||
|
||||
fun sharedPath(): Path {
|
||||
sharedPath.reset()
|
||||
return sharedPath
|
||||
}
|
||||
|
||||
fun sharedPath2(): Path {
|
||||
sharedPath2.reset()
|
||||
return sharedPath2
|
||||
}
|
||||
|
||||
fun sharedMatrix(): Matrix {
|
||||
sharedMatrix.reset()
|
||||
return sharedMatrix
|
||||
}
|
||||
|
||||
fun sharedMatrix2(): Matrix {
|
||||
sharedMatrix2.reset()
|
||||
return sharedMatrix2
|
||||
}
|
||||
|
||||
fun shareMattePaint(): Paint {
|
||||
shareMattePaint.setXfermode(PorterDuffXfermode(PorterDuff.Mode.DST_IN))
|
||||
return shareMattePaint
|
||||
}
|
||||
|
||||
fun sharedMatteBitmap(): Bitmap {
|
||||
return sharedMatteBitmap as Bitmap
|
||||
}
|
||||
|
||||
fun shareMatteCanvas(width: Int, height: Int): Canvas {
|
||||
if (shareMatteCanvas == null) {
|
||||
sharedMatteBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8)
|
||||
// shareMatteCanvas = Canvas(sharedMatteBitmap)
|
||||
}
|
||||
// val matteCanvas = shareMatteCanvas as Canvas
|
||||
// matteCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
|
||||
// return matteCanvas
|
||||
return Canvas(sharedMatteBitmap)
|
||||
}
|
||||
}
|
||||
|
||||
class PathCache {
|
||||
|
||||
private var canvasWidth: Int = 0
|
||||
private var canvasHeight: Int = 0
|
||||
private val cache = HashMap<SVGAVideoShapeEntity, Path>()
|
||||
|
||||
fun onSizeChanged(canvas: Canvas) {
|
||||
if (this.canvasWidth != canvas.width || this.canvasHeight != canvas.height) {
|
||||
this.cache.clear()
|
||||
}
|
||||
this.canvasWidth = canvas.width
|
||||
this.canvasHeight = canvas.height
|
||||
}
|
||||
|
||||
fun buildPath(shape: SVGAVideoShapeEntity): Path {
|
||||
if (!this.cache.containsKey(shape)) {
|
||||
val path = Path()
|
||||
path.set(shape.shapePath)
|
||||
this.cache[shape] = path
|
||||
}
|
||||
return this.cache[shape]!!
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user