Add raw resource decoder
This commit is contained in:
parent
887d679c4b
commit
5bb270132f
|
@ -20,6 +20,7 @@ import java.util.zip.CRC32
|
|||
/**
|
||||
* Create an APNG file
|
||||
*/
|
||||
@Suppress("unused")
|
||||
class Apng {
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
var maxWidth : Int? = null
|
||||
|
@ -45,7 +46,6 @@ class Apng {
|
|||
* @param disposeOp `DisposeOp` specifies how the output buffer should be changed at the end of the delay (before rendering the next frame).
|
||||
* @param blendOp `BlendOp` specifies whether the frame is to be alpha blended into the current output buffer content, or whether it should completely replace its region in the output buffer.
|
||||
*/
|
||||
|
||||
fun addFrames(bitmap : Bitmap, index : Int? = null, delay : Float = 1000f, xOffset : Int = 0, yOffset : Int = 0, disposeOp: Utils.Companion.DisposeOp = Utils.Companion.DisposeOp.APNG_DISPOSE_OP_NONE, blendOp: Utils.Companion.BlendOp = Utils.Companion.BlendOp.APNG_BLEND_OP_SOURCE) {
|
||||
if (index == null)
|
||||
frames.add(Frame(PngEncoder.encode(bitmap, true), delay, xOffset, yOffset, blendOp, disposeOp))
|
||||
|
@ -53,7 +53,6 @@ class Apng {
|
|||
frames.add(index, Frame(PngEncoder.encode(bitmap, true), delay, xOffset, yOffset, blendOp, disposeOp))
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun addFrames(frame : Frame, index: Int? = null) {
|
||||
if (index == null)
|
||||
frames.add(frame)
|
||||
|
@ -95,6 +94,7 @@ class Apng {
|
|||
|
||||
// Add the frame number
|
||||
fcTL.addAll(to4Bytes(seq).toList())
|
||||
|
||||
// foreach fcTL or fdAT we must increment seq
|
||||
seq++
|
||||
|
||||
|
@ -102,6 +102,7 @@ class Apng {
|
|||
fcTL.addAll(to4Bytes(frames[0].width).toList())
|
||||
fcTL.addAll(to4Bytes(frames[0].height).toList())
|
||||
|
||||
// Add offsets
|
||||
fcTL.addAll(to4Bytes(frames[0].xOffsets).toList())
|
||||
fcTL.addAll(to4Bytes(frames[0].yOffsets).toList())
|
||||
|
||||
|
@ -369,7 +370,6 @@ class Apng {
|
|||
* @param keepCover Keep the cover
|
||||
* @param sizePercent Reduce image width/height by percents.
|
||||
*/
|
||||
@Suppress("unused")
|
||||
fun reduceSize(maxColor : Int, keepCover : Boolean? = null, sizePercent : Int? = null) {
|
||||
val apng = Apng()
|
||||
if (keepCover != false) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import android.content.SharedPreferences
|
|||
import android.graphics.*
|
||||
import android.net.Uri
|
||||
import android.widget.ImageView
|
||||
import androidx.annotation.RawRes
|
||||
import org.jetbrains.anko.doAsync
|
||||
import org.jetbrains.anko.runOnUiThread
|
||||
import org.jetbrains.anko.uiThread
|
||||
|
@ -19,7 +20,7 @@ import java.net.URL
|
|||
fun ImageView.loadApng(file: File, speed: Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) = ApngAnimator(this.context).loadInto(this).apply {
|
||||
load(file, speed, apngAnimatorOptions)
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun ImageView.loadApng(uri : Uri, speed: Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) = ApngAnimator(this.context).loadInto(this).apply {
|
||||
load(uri, speed, apngAnimatorOptions)
|
||||
}
|
||||
|
@ -31,9 +32,14 @@ fun ImageView.loadApng(url: URL, speed: Float? = null, apngAnimatorOptions: Apng
|
|||
fun ImageView.loadApng(byteArray: ByteArray, speed: Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) = ApngAnimator(this.context).loadInto(this).apply {
|
||||
load(byteArray, speed, apngAnimatorOptions)
|
||||
}
|
||||
@Suppress("unused")
|
||||
fun ImageView.loadApng(string: String, speed : Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) = ApngAnimator(this.context).loadInto(this).apply {
|
||||
load(string, speed, apngAnimatorOptions)
|
||||
}
|
||||
@Suppress("unused")
|
||||
fun ImageView.loadApng(@RawRes res : Int, speed : Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) = ApngAnimator(this.context).loadInto(this).apply {
|
||||
load(res, speed, apngAnimatorOptions)
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to play APNG
|
||||
|
@ -56,20 +62,26 @@ class ApngAnimator(private val context: Context?) {
|
|||
}
|
||||
}
|
||||
private var imageView: ImageView? = null
|
||||
|
||||
var anim: CustomAnimationDrawable? = null
|
||||
private var activeAnimation: CustomAnimationDrawable? = null
|
||||
|
||||
private var doOnLoaded : (ApngAnimator) -> Unit = {}
|
||||
@Suppress("PrivatePropertyName")
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
private var AnimationLoopListener : () -> Unit = {}
|
||||
private var animationLoopListener : () -> Unit = {}
|
||||
|
||||
private var duration : ArrayList<Float>? = null
|
||||
|
||||
private var scaleType : ImageView.ScaleType? = null
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
var isApng = false
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
var loadNotApng = true
|
||||
|
||||
private val sharedPreferences : SharedPreferences? = context?.getSharedPreferences("apngAnimator", Context.MODE_PRIVATE)
|
||||
private val sharedPreferences : SharedPreferences? by lazy {
|
||||
context?.getSharedPreferences("apngAnimator", Context.MODE_PRIVATE)
|
||||
}
|
||||
|
||||
init {
|
||||
loadNotApng = sharedPreferences?.getBoolean("loadNotApng", true) ?: true
|
||||
|
@ -87,7 +99,7 @@ class ApngAnimator(private val context: Context?) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Load into an imageview
|
||||
* Load into an ImageView
|
||||
* @param imageView Image view selected.
|
||||
*/
|
||||
fun loadInto(imageView: ImageView): ApngAnimator {
|
||||
|
@ -111,8 +123,8 @@ class ApngAnimator(private val context: Context?) {
|
|||
this@ApngAnimator.speed = speed
|
||||
scaleType = apngAnimatorOptions?.scaleType
|
||||
// Download PNG
|
||||
APNGDisassembler.disassemble(bytes).frames.apply {
|
||||
draw(this).apply {
|
||||
APNGDisassembler.disassemble(bytes).frames.also {frames ->
|
||||
draw(frames).apply {
|
||||
setupAnimationDrawableAndStart(this)
|
||||
}
|
||||
}
|
||||
|
@ -144,8 +156,8 @@ class ApngAnimator(private val context: Context?) {
|
|||
this@ApngAnimator.speed = speed
|
||||
scaleType = apngAnimatorOptions?.scaleType
|
||||
// Download PNG
|
||||
APNGDisassembler.disassemble(it).frames.apply {
|
||||
draw(this).apply {
|
||||
APNGDisassembler.disassemble(it).frames.also {frames ->
|
||||
draw(frames).apply {
|
||||
setupAnimationDrawableAndStart(this)
|
||||
}
|
||||
}
|
||||
|
@ -181,8 +193,8 @@ class ApngAnimator(private val context: Context?) {
|
|||
this@ApngAnimator.speed = speed
|
||||
scaleType = apngAnimatorOptions?.scaleType
|
||||
// Download PNG
|
||||
APNGDisassembler.disassemble(this).frames.apply {
|
||||
draw(this).apply {
|
||||
APNGDisassembler.disassemble(this).frames.also { frames ->
|
||||
draw(frames).apply {
|
||||
setupAnimationDrawableAndStart(this)
|
||||
}
|
||||
}
|
||||
|
@ -218,8 +230,8 @@ class ApngAnimator(private val context: Context?) {
|
|||
this@ApngAnimator.speed = speed
|
||||
scaleType = apngAnimatorOptions?.scaleType
|
||||
// Download PNG
|
||||
APNGDisassembler.disassemble(byteArray).frames.apply {
|
||||
draw(this).apply {
|
||||
APNGDisassembler.disassemble(byteArray).frames.also { frames ->
|
||||
draw(frames).apply {
|
||||
setupAnimationDrawableAndStart(this)
|
||||
}
|
||||
}
|
||||
|
@ -270,6 +282,34 @@ class ApngAnimator(private val context: Context?) {
|
|||
return this
|
||||
}
|
||||
|
||||
fun load(@RawRes res : Int, speed : Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) : ApngAnimator {
|
||||
doAsync {
|
||||
val byteArray = context?.resources?.openRawResource(res)?.readBytes() ?: byteArrayOf()
|
||||
this@ApngAnimator.speed = speed
|
||||
if (isApng(byteArray)) {
|
||||
isApng = true
|
||||
this@ApngAnimator.speed = speed
|
||||
scaleType = apngAnimatorOptions?.scaleType
|
||||
// Download PNG
|
||||
APNGDisassembler.disassemble(byteArray).frames.also { frames ->
|
||||
draw(frames).apply {
|
||||
setupAnimationDrawableAndStart(this)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (loadNotApng) {
|
||||
context?.runOnUiThread {
|
||||
imageView?.scaleType = this@ApngAnimator.scaleType ?: ImageView.ScaleType.FIT_CENTER
|
||||
imageView?.setImageBitmap(BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size))
|
||||
}
|
||||
} else {
|
||||
throw NotApngException()
|
||||
}
|
||||
}
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the animation drawable and any required listeners. The animation will automatically start.
|
||||
*/
|
||||
|
@ -360,7 +400,7 @@ class ApngAnimator(private val context: Context?) {
|
|||
}
|
||||
activeAnimation = animResume
|
||||
imageView?.setImageDrawable(activeAnimation)
|
||||
activeAnimation?.setOnAnimationLoopListener(AnimationLoopListener)
|
||||
activeAnimation?.setOnAnimationLoopListener(animationLoopListener)
|
||||
imageView?.invalidate()
|
||||
duration = dura
|
||||
break@frameLoop
|
||||
|
@ -385,7 +425,7 @@ class ApngAnimator(private val context: Context?) {
|
|||
*/
|
||||
fun setOnAnimationLoopListener(animationLoopListener : () -> Unit) {
|
||||
if (isApng) {
|
||||
AnimationLoopListener = animationLoopListener
|
||||
this.animationLoopListener = animationLoopListener
|
||||
anim?.setOnAnimationLoopListener(animationLoopListener)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import androidx.annotation.ColorInt
|
|||
import oupson.apng.utils.Utils
|
||||
import java.util.*
|
||||
|
||||
// TODO Work on this class
|
||||
class BitmapDiffCalculator(firstBitmap: Bitmap, secondBitmap : Bitmap) {
|
||||
val res : Bitmap
|
||||
var xOffset : Int = 0
|
||||
|
|
|
@ -38,7 +38,18 @@ class Utils {
|
|||
/**
|
||||
* Signature for png / APNG files
|
||||
*/
|
||||
val pngSignature: ByteArray = byteArrayOf(0x89.toByte(), 0x50.toByte(), 0x4E.toByte(), 0x47.toByte(), 0x0D.toByte(), 0x0A.toByte(), 0x1A.toByte(), 0x0A.toByte())
|
||||
val pngSignature: ByteArray by lazy {
|
||||
byteArrayOf(
|
||||
0x89.toByte(),
|
||||
0x50.toByte(),
|
||||
0x4E.toByte(),
|
||||
0x47.toByte(),
|
||||
0x0D.toByte(),
|
||||
0x0A.toByte(),
|
||||
0x1A.toByte(),
|
||||
0x0A.toByte()
|
||||
)
|
||||
}
|
||||
|
||||
enum class DisposeOp {
|
||||
APNG_DISPOSE_OP_NONE,
|
||||
|
@ -137,12 +148,12 @@ class Utils {
|
|||
return lengthString.toLong(16).toInt()
|
||||
}
|
||||
|
||||
val fcTL : String = Arrays.toString(byteArrayOf(0x66, 0x63, 0x54, 0x4c))
|
||||
val IEND : String = Arrays.toString(byteArrayOf(0x49, 0x45, 0x4e, 0x44))
|
||||
val IDAT : String = Arrays.toString(byteArrayOf(0x49, 0x44, 0x41, 0x54))
|
||||
val fdAT : String = Arrays.toString(byteArrayOf(0x66, 0x64, 0x41, 0x54))
|
||||
val plte : String = Arrays.toString(byteArrayOf(0x50, 0x4c, 0x54, 0x45))
|
||||
val tnrs : String = Arrays.toString(byteArrayOf(0x74, 0x52, 0x4e, 0x53))
|
||||
val IHDR : String = Arrays.toString(byteArrayOf(0x49, 0x48, 0x44, 0x52))
|
||||
val fcTL : String by lazy { Arrays.toString(byteArrayOf(0x66, 0x63, 0x54, 0x4c)) }
|
||||
val IEND : String by lazy { Arrays.toString(byteArrayOf(0x49, 0x45, 0x4e, 0x44)) }
|
||||
val IDAT : String by lazy { Arrays.toString(byteArrayOf(0x49, 0x44, 0x41, 0x54)) }
|
||||
val fdAT : String by lazy { Arrays.toString(byteArrayOf(0x66, 0x64, 0x41, 0x54)) }
|
||||
val plte : String by lazy { Arrays.toString(byteArrayOf(0x50, 0x4c, 0x54, 0x45)) }
|
||||
val tnrs : String by lazy { Arrays.toString(byteArrayOf(0x74, 0x52, 0x4e, 0x53)) }
|
||||
val IHDR : String by lazy { Arrays.toString(byteArrayOf(0x49, 0x48, 0x44, 0x52)) }
|
||||
}
|
||||
}
|
|
@ -123,7 +123,7 @@ class MainActivity : AppCompatActivity() {
|
|||
)
|
||||
val imageView = imageView {
|
||||
id = View.generateViewId()
|
||||
animator = this.loadApng(imageUrl).apply {
|
||||
animator = this.loadApng(R.raw.bugbuckbunny).apply {
|
||||
onLoaded {
|
||||
setOnAnimationLoopListener {
|
||||
// Log.e("app-test", "onLoop")
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.7 MiB |
Loading…
Reference in New Issue