diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser
index 2b4ce54..b28f89c 100644
Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..73ab2c8
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apng_library/src/main/AndroidManifest.xml b/apng_library/src/main/AndroidManifest.xml
index b2ea72a..a6585f3 100644
--- a/apng_library/src/main/AndroidManifest.xml
+++ b/apng_library/src/main/AndroidManifest.xml
@@ -1,2 +1,4 @@
+ package="oupson.apng">
+
+
diff --git a/apng_library/src/main/java/oupson/apng/APNGDisassembler.kt b/apng_library/src/main/java/oupson/apng/APNGDisassembler.kt
index 93ba2a1..532c22f 100644
--- a/apng_library/src/main/java/oupson/apng/APNGDisassembler.kt
+++ b/apng_library/src/main/java/oupson/apng/APNGDisassembler.kt
@@ -1,25 +1,32 @@
package oupson.apng
import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.Canvas
import android.util.Log
-import oupson.apng.ApngFactory.Companion.isApng
-import oupson.apng.ApngFactory.Companion.isApng
import oupson.apng.ApngFactory.Companion.pngSignature
import java.util.zip.CRC32
-
class APNGDisassembler(val byteArray: ByteArray) {
val pngList = ArrayList()
var png : ArrayList? = null
+ var cover : ArrayList? = null
+
var delay = -1f
var yOffset= -1
var xOffset = -1
+ var plte : ByteArray? = null
+ var tnrs : ByteArray? = null
+
var maxWidth = 0
var maxHeight = 0
+
+ var blend_op : Utils.Companion.blend_op = Utils.Companion.blend_op.APNG_BLEND_OP_SOURCE
+ var dispose_op : Utils.Companion.dispose_op= Utils.Companion.dispose_op.APNG_DISPOSE_OP_NONE
init {
if (ApngFactory.isApng(byteArray)) {
val ihdr = IHDR()
@@ -30,17 +37,36 @@ class APNGDisassembler(val byteArray: ByteArray) {
// find new Frame with fcTL
if (byteArray[i] == 0x66.toByte() && byteArray[i + 1] == 0x63.toByte() && byteArray[ i + 2 ] == 0x54.toByte() && byteArray[ i + 3 ] == 0x4C.toByte() || i == byteArray.size - 1) {
if (png == null) {
+ if (cover != null) {
+ cover!!.addAll(to4Bytes(0).toList())
+ // Add IEND
+ val iend = byteArrayOf(0x49, 0x45, 0x4E, 0x44)
+ // Generate crc for IEND
+ val crC32 = CRC32()
+ crC32.update(iend, 0, iend.size)
+ cover!!.addAll(iend.toList())
+ cover!!.addAll(to4Bytes(crC32.value.toInt()).toList())
+ }
png = ArrayList()
- val fcTL = fcTL(byteArray.copyOfRange(i-4, i + 28))
+ val fcTL = fcTL(byteArray.copyOfRange(i-4, i + 32))
delay = fcTL.delay
yOffset = fcTL.y_offset
xOffset = fcTL.x_offset
- Log.e("APNG", "delay : + ${fcTL.delay}")
+ blend_op = fcTL.blend_op
+ dispose_op = fcTL.dispose_op
val width = fcTL.pngWidth
val height = fcTL.pngHeight
png!!.addAll(pngSignature.toList())
png!!.addAll(generate_ihdr(ihdr, width, height).toList())
+
+ if (plte != null) {
+ png!!.addAll(plte!!.toList())
+ }
+
+ if (tnrs != null) {
+ png!!.addAll(tnrs!!.toList())
+ }
} else {
// Add IEND body length : 0
png!!.addAll(to4Bytes(0).toList())
@@ -51,22 +77,78 @@ class APNGDisassembler(val byteArray: ByteArray) {
crC32.update(iend, 0, iend.size)
png!!.addAll(iend.toList())
png!!.addAll(to4Bytes(crC32.value.toInt()).toList())
- pngList.add(Frame(png!!.toByteArray(), delay, xOffset, yOffset, maxWidth, maxHeight))
+ pngList.add(Frame(png!!.toByteArray(), delay, xOffset, yOffset, maxWidth, maxHeight, blend_op, dispose_op))
png = ArrayList()
- val fcTL = fcTL(byteArray.copyOfRange(i-4, i + 28))
+ val fcTL = fcTL(byteArray.copyOfRange(i-4, i + 32))
delay = fcTL.delay
yOffset = fcTL.y_offset
xOffset = fcTL.x_offset
+ blend_op = fcTL.blend_op
+ dispose_op = fcTL.dispose_op
val width = fcTL.pngWidth
val height = fcTL.pngHeight
png!!.addAll(pngSignature.toList())
png!!.addAll(generate_ihdr(ihdr, width, height).toList())
+ if (plte != null) {
+ png!!.addAll(plte!!.toList())
+ }
+
+ if (tnrs != null) {
+ png!!.addAll(tnrs!!.toList())
+ }
}
- } else if (byteArray[i] == 0x49.toByte() && byteArray[i + 1] == 0x44.toByte() && byteArray[ i + 2 ] == 0x41.toByte() && byteArray[ i + 3 ] == 0x54.toByte()) {
+ }
+ // Check if is IDAT
+ else if (byteArray[i] == 0x49.toByte() && byteArray[i + 1] == 0x44.toByte() && byteArray[ i + 2 ] == 0x41.toByte() && byteArray[ i + 3 ] == 0x54.toByte()) {
+ if (png == null) {
+ if (cover == null) {
+ cover = ArrayList()
+ png!!.addAll(pngSignature.toList())
+ png!!.addAll(generate_ihdr(ihdr, maxWidth, maxHeight).toList())
+ }
+ // Find the chunk length
+ var lengthString = ""
+ byteArray.copyOfRange( i - 4, i).forEach {
+ lengthString += String.format("%02x", it)
+ }
+ val bodySize = lengthString.toLong(16).toInt()
+ cover!!.addAll(byteArray.copyOfRange(i-4, i).toList())
+ val body = ArrayList()
+ body.addAll(byteArrayOf(0x49, 0x44, 0x41, 0x54).toList())
+ // Get image bytes
+ for (j in i +4 until i + 4 + bodySize) {
+ body.add(byteArray[j])
+ }
+ val crC32 = CRC32()
+ crC32.update(body.toByteArray(), 0, body.size)
+ cover!!.addAll(body)
+ cover!!.addAll(to4Bytes(crC32.value.toInt()).toList())
+ } else {
+ // Find the chunk length
+ var lengthString = ""
+ byteArray.copyOfRange( i - 4, i).forEach {
+ lengthString += String.format("%02x", it)
+ }
+ val bodySize = lengthString.toLong(16).toInt()
+ png!!.addAll(byteArray.copyOfRange(i-4, i).toList())
+ val body = ArrayList()
+ body.addAll(byteArrayOf(0x49, 0x44, 0x41, 0x54).toList())
+ // Get image bytes
+ for (j in i +4 until i + 4 + bodySize) {
+ body.add(byteArray[j])
+ }
+ val crC32 = CRC32()
+ crC32.update(body.toByteArray(), 0, body.size)
+ png!!.addAll(body)
+ png!!.addAll(to4Bytes(crC32.value.toInt()).toList())
+ }
+ }
+ // Check if is fdAT
+ else if (byteArray[i] == 0x66.toByte() && byteArray[i + 1] == 0x64.toByte() && byteArray[ i + 2 ] == 0x41.toByte() && byteArray[ i + 3 ] == 0x54.toByte()) {
// Find the chunk length
var lengthString = ""
byteArray.copyOfRange( i - 4, i).forEach {
@@ -75,47 +157,37 @@ class APNGDisassembler(val byteArray: ByteArray) {
val bodySize = lengthString.toLong(16).toInt()
- png!!.addAll(byteArray.copyOfRange(i-4, i).toList())
- val body = ArrayList()
- body.addAll(byteArrayOf(0x49, 0x44, 0x41, 0x54).toList())
- // Get image bytes
-
- for (j in i +4 until i + 4 + bodySize) {
- body.add(byteArray[j])
- }
-
- val crC32 = CRC32()
- crC32.update(body.toByteArray(), 0, body.size)
- png!!.addAll(body)
- png!!.addAll(to4Bytes(crC32.value.toInt()).toList())
- } else if (byteArray[i] == 0x66.toByte() && byteArray[i + 1] == 0x64.toByte() && byteArray[ i + 2 ] == 0x41.toByte() && byteArray[ i + 3 ] == 0x54.toByte()) {
- // Find the chunk length
- var lengthString = ""
- byteArray.copyOfRange( i - 4, i).forEach {
- lengthString += String.format("%02x", it)
- }
-
-
- var bodySize = lengthString.toLong(16).toInt()
png!!.addAll(to4Bytes(bodySize - 4).toList())
val body = ArrayList()
body.addAll(byteArrayOf(0x49, 0x44, 0x41, 0x54).toList())
// Get image bytes
-
for (j in i + 8 until i + 4 + bodySize) {
body.add(byteArray[j])
}
-
val crC32 = CRC32()
crC32.update(body.toByteArray(), 0, body.size)
png!!.addAll(body)
png!!.addAll(to4Bytes(crC32.value.toInt()).toList())
+ } else if (byteArray[i] == 0x50.toByte() && byteArray[i + 1] == 0x4C.toByte() && byteArray[ i + 2 ] == 0x54.toByte() && byteArray[ i + 3 ] == 0x45.toByte()) {
+ var lengthString = ""
+ byteArray.copyOfRange( i - 4, i).forEach {
+ lengthString += String.format("%02x", it)
+ }
+ val bodySize = lengthString.toLong(16).toInt()
+ val body = ArrayList()
+ plte = byteArray.copyOfRange( i -4, i + 8 + bodySize)
+ }
+ else if (byteArray[i] == 0x74.toByte() && byteArray[i + 1] == 0x52.toByte() && byteArray[ i + 2 ] == 0x4E.toByte() && byteArray[ i + 3 ] == 0x53.toByte()) {
+ var lengthString = ""
+ byteArray.copyOfRange( i - 4, i).forEach {
+ lengthString += String.format("%02x", it)
+ }
+ val bodySize = lengthString.toLong(16).toInt()
+ val body = ArrayList()
+ tnrs = byteArray.copyOfRange( i -4, i + 8 + bodySize)
}
}
} else {
- var p = ""
- p += String(byteArray.copyOfRange(0, 50))
- Log.e("TAG", "Not a apng : $p")
throw NotApngException()
}
}
@@ -169,6 +241,17 @@ class APNGDisassembler(val byteArray: ByteArray) {
return result
}
+ fun genBitmap() : ArrayList {
+ val generatedFrame = ArrayList()
+ pngList.forEach {
+ val btm = Bitmap.createBitmap(it.maxWidth, it.maxHeight, Bitmap.Config.ARGB_8888)
+ val canvas = Canvas(btm)
+ canvas.drawBitmap(BitmapFactory.decodeByteArray(it.byteArray, 0, it.byteArray.size), it.x_offsets.toFloat(), it.y_offsets.toFloat(), null)
+ generatedFrame.add(btm)
+ }
+ return generatedFrame
+ }
+
}
\ No newline at end of file
diff --git a/apng_library/src/main/java/oupson/apng/ApngAnimator.kt b/apng_library/src/main/java/oupson/apng/ApngAnimator.kt
index b8837c1..e0d50b2 100644
--- a/apng_library/src/main/java/oupson/apng/ApngAnimator.kt
+++ b/apng_library/src/main/java/oupson/apng/ApngAnimator.kt
@@ -1,89 +1,247 @@
package oupson.apng
-import android.graphics.Bitmap
-import android.graphics.BitmapFactory
-import android.graphics.Canvas
+import android.graphics.*
import android.os.Environment
import android.os.Handler
import android.widget.ImageView
import org.jetbrains.anko.doAsync
import org.jetbrains.anko.uiThread
import java.io.File
+import java.io.FileOutputStream
+import java.io.IOException
import java.net.URL
+
class ApngAnimator(val imageView : ImageView) {
var play = true
+
var Frames = ArrayList()
+
var myHandler: Handler
+
var counter = 0
val generatedFrame = ArrayList()
+ var speed = 1
+
+ var lastFrame : Frame? = null
+ var bitmapBuffer : Bitmap? = null
+
+ var background : Bitmap? = null
+
+ var isDebug = false
+
init {
myHandler = Handler()
-
-
}
- fun load(file: File) {
- val extractedFrame = APNGDisassembler(file.readBytes()).pngList
- Frames = extractedFrame
- Frames.forEach {
+ fun load(file: File) {
+ // Download PNG
+ val extractedFrame = APNGDisassembler(file.readBytes()).pngList
+
+ // Set last frame
+ lastFrame = extractedFrame[0]
+
+ // Init image buffer
+ bitmapBuffer = BitmapFactory.decodeByteArray(lastFrame?.byteArray, 0, lastFrame?.byteArray!!.size)
+ generatedFrame.add(BitmapFactory.decodeByteArray(lastFrame?.byteArray, 0, lastFrame?.byteArray!!.size))
+ Frames = extractedFrame
+ for (i in 1 until Frames.size) {
+ // Iterator
+ val it = Frames.get(i)
+
+ // Current bitmap for the frame
val btm = Bitmap.createBitmap(Frames[0].maxWidth, Frames[0].maxHeight, Bitmap.Config.ARGB_8888)
val canvas = Canvas(btm)
- canvas.drawBitmap(BitmapFactory.decodeByteArray(it.byteArray, 0, it.byteArray.size), it.x_offsets.toFloat(), it.y_offsets.toFloat(), null)
- generatedFrame.add(btm)
- }
+ val current = BitmapFactory.decodeByteArray(it.byteArray, 0, it.byteArray.size).copy(Bitmap.Config.ARGB_8888, true)
+
+ // Write buffer to canvas
+ canvas.drawBitmap(bitmapBuffer, 0f, 0f, null)
+
+ // APNG_DISPOSE_OP_BACKGROUND: the frame's region of the output buffer is to be cleared to fully transparent black before rendering the next frame.
+ if (lastFrame!!.dispose_op == Utils.Companion.dispose_op.APNG_DISPOSE_OP_BACKGROUND) {
+ canvas.drawRect(lastFrame!!.x_offsets.toFloat(), lastFrame!!.y_offsets.toFloat(), lastFrame!!.x_offsets + lastFrame!!.width.toFloat(), lastFrame!!.y_offsets + lastFrame!!.height.toFloat(), { val paint = Paint(); paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR); paint }())
+ }
+
+ // Clear current frame rect
+ // If `blend_op` is APNG_BLEND_OP_SOURCE all color components of the frame, including alpha, overwrite the current contents of the frame's output buffer region.
+ if (it.blend_op == Utils.Companion.blend_op.APNG_BLEND_OP_SOURCE) {
+ canvas.drawRect(it.x_offsets.toFloat(), it.y_offsets.toFloat(), it.x_offsets + current.width.toFloat(), it.y_offsets + current.height.toFloat(), { val paint = Paint(); paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR); paint }())
+ }
+
+ // Draw the bitmap
+ canvas.drawBitmap(current, it.x_offsets.toFloat(), it.y_offsets.toFloat(), null)
+ generatedFrame.add(btm)
+
+ // Don't add current frame to bitmap buffer
+ if (Frames[i].dispose_op == Utils.Companion.dispose_op.APNG_DISPOSE_OP_PREVIOUS) {
+ //Do nothings
+ }
+ // Add current frame to bitmap buffer
+ else {
+ bitmapBuffer = btm
+ }
+ }
+ // DEBUG FUNCTION : WRITE RENDERED FRAME TO EXTERNAL STORAGE
+ if (isDebug) {
+ for (i in 0 until generatedFrame.size) {
+ try {
+ FileOutputStream(File(File(Environment.getExternalStorageDirectory(), "Documents"), "image_$i.png")).use { out ->
+ generatedFrame[i].compress(Bitmap.CompressFormat.PNG, 100, out) // bmp is your Bitmap instance
+ // PNG is a lossless format, the compression factor (100) is ignored
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ nextFrame()
+ }
+
+ private fun loadUrl(url : URL) {
+ doAsync(exceptionHandler = {e -> e.printStackTrace()}) {
+ // Download PNG
+ val extractedFrame = APNGDisassembler(Loader().load(url)).pngList
+
+ // Set last frame
+ lastFrame = extractedFrame[0]
+
+ // Init image buffer
+ bitmapBuffer = BitmapFactory.decodeByteArray(lastFrame?.byteArray, 0, lastFrame?.byteArray!!.size)
+ generatedFrame.add(BitmapFactory.decodeByteArray(lastFrame?.byteArray, 0, lastFrame?.byteArray!!.size))
+ Frames = extractedFrame
+ for (i in 1 until Frames.size) {
+ // Iterator
+ val it = Frames.get(i)
+
+ // Current bitmap for the frame
+ val btm = Bitmap.createBitmap(Frames[0].maxWidth, Frames[0].maxHeight, Bitmap.Config.ARGB_8888)
+ val canvas = Canvas(btm)
+
+ val current = BitmapFactory.decodeByteArray(it.byteArray, 0, it.byteArray.size).copy(Bitmap.Config.ARGB_8888, true)
+
+ // Write buffer to canvas
+ canvas.drawBitmap(bitmapBuffer, 0f, 0f, null)
+
+ // APNG_DISPOSE_OP_BACKGROUND: the frame's region of the output buffer is to be cleared to fully transparent black before rendering the next frame.
+ if (lastFrame!!.dispose_op == Utils.Companion.dispose_op.APNG_DISPOSE_OP_BACKGROUND) {
+ canvas.drawRect(lastFrame!!.x_offsets.toFloat(), lastFrame!!.y_offsets.toFloat(), lastFrame!!.x_offsets + lastFrame!!.width.toFloat(),lastFrame!!.y_offsets + lastFrame!!.height.toFloat(), {val paint = Paint(); paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR); paint}())
+ }
+
+ // Clear current frame rect
+ // If `blend_op` is APNG_BLEND_OP_SOURCE all color components of the frame, including alpha, overwrite the current contents of the frame's output buffer region.
+ if (it.blend_op == Utils.Companion.blend_op.APNG_BLEND_OP_SOURCE) {
+ canvas.drawRect(it.x_offsets.toFloat(), it.y_offsets.toFloat(), it.x_offsets + current.width.toFloat(),it.y_offsets + current.height.toFloat(), {val paint = Paint(); paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR); paint}())
+ }
+
+ // Draw the bitmap
+ canvas.drawBitmap(current, it.x_offsets.toFloat(), it.y_offsets.toFloat(), null)
+ generatedFrame.add(btm)
+
+ // Don't add current frame to bitmap buffer
+ if (Frames[i].dispose_op == Utils.Companion.dispose_op.APNG_DISPOSE_OP_PREVIOUS) {
+ //Do nothings
+ }
+ // Add current frame to bitmap buffer
+ else {
+ bitmapBuffer = btm
+ }
+ }
+ // DEBUG FUNCTION : WRITE RENDERED FRAME TO EXTERNAL STORAGE
+ if (isDebug) {
+ for (i in 0 until generatedFrame.size) {
+ try {
+ FileOutputStream(File(File(Environment.getExternalStorageDirectory(), "Documents"), "image_$i.png")).use { out ->
+ generatedFrame[i].compress(Bitmap.CompressFormat.PNG, 100, out) // bmp is your Bitmap instance
+ // PNG is a lossless format, the compression factor (100) is ignored
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ uiThread {
+ nextFrame()
+ }
+ }
+ }
+
+ fun load(byteArray: ByteArray) {
+ // Download PNG
+ val extractedFrame = APNGDisassembler(byteArray).pngList
+
+ // Set last frame
+ lastFrame = extractedFrame[0]
+
+ // Init image buffer
+ bitmapBuffer = BitmapFactory.decodeByteArray(lastFrame?.byteArray, 0, lastFrame?.byteArray!!.size)
+ generatedFrame.add(BitmapFactory.decodeByteArray(lastFrame?.byteArray, 0, lastFrame?.byteArray!!.size))
+ Frames = extractedFrame
+ for (i in 1 until Frames.size) {
+ // Iterator
+ val it = Frames.get(i)
+
+ // Current bitmap for the frame
+ val btm = Bitmap.createBitmap(Frames[0].maxWidth, Frames[0].maxHeight, Bitmap.Config.ARGB_8888)
+ val canvas = Canvas(btm)
+
+ val current = BitmapFactory.decodeByteArray(it.byteArray, 0, it.byteArray.size).copy(Bitmap.Config.ARGB_8888, true)
+
+ // Write buffer to canvas
+ canvas.drawBitmap(bitmapBuffer, 0f, 0f, null)
+
+ // APNG_DISPOSE_OP_BACKGROUND: the frame's region of the output buffer is to be cleared to fully transparent black before rendering the next frame.
+ if (lastFrame!!.dispose_op == Utils.Companion.dispose_op.APNG_DISPOSE_OP_BACKGROUND) {
+ canvas.drawRect(lastFrame!!.x_offsets.toFloat(), lastFrame!!.y_offsets.toFloat(), lastFrame!!.x_offsets + lastFrame!!.width.toFloat(), lastFrame!!.y_offsets + lastFrame!!.height.toFloat(), { val paint = Paint(); paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR); paint }())
+ }
+
+ // Clear current frame rect
+ // If `blend_op` is APNG_BLEND_OP_SOURCE all color components of the frame, including alpha, overwrite the current contents of the frame's output buffer region.
+ if (it.blend_op == Utils.Companion.blend_op.APNG_BLEND_OP_SOURCE) {
+ canvas.drawRect(it.x_offsets.toFloat(), it.y_offsets.toFloat(), it.x_offsets + current.width.toFloat(), it.y_offsets + current.height.toFloat(), { val paint = Paint(); paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR); paint }())
+ }
+
+ // Draw the bitmap
+ canvas.drawBitmap(current, it.x_offsets.toFloat(), it.y_offsets.toFloat(), null)
+ generatedFrame.add(btm)
+
+ // Don't add current frame to bitmap buffer
+ if (Frames[i].dispose_op == Utils.Companion.dispose_op.APNG_DISPOSE_OP_PREVIOUS) {
+ //Do nothings
+ }
+ // Add current frame to bitmap buffer
+ else {
+ bitmapBuffer = btm
+ }
+ }
+ // DEBUG FUNCTION : WRITE RENDERED FRAME TO EXTERNAL STORAGE
+ if (isDebug) {
+ for (i in 0 until generatedFrame.size) {
+ try {
+ FileOutputStream(File(File(Environment.getExternalStorageDirectory(), "Documents"), "image_$i.png")).use { out ->
+ generatedFrame[i].compress(Bitmap.CompressFormat.PNG, 100, out) // bmp is your Bitmap instance
+ // PNG is a lossless format, the compression factor (100) is ignored
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ }
nextFrame()
}
fun load(string: String) {
if (string.contains("http") || string.contains("https")) {
val url = URL(string)
- doAsync {
- val extractedFrame = APNGDisassembler(Loader().load(url)).pngList
- Frames = extractedFrame
-
- Frames.forEach {
- val btm = Bitmap.createBitmap(Frames[0].maxWidth, Frames[0].maxHeight, Bitmap.Config.ARGB_8888)
- val canvas = Canvas(btm)
- canvas.drawBitmap(BitmapFactory.decodeByteArray(it.byteArray, 0, it.byteArray.size), it.x_offsets.toFloat(), it.y_offsets.toFloat(), null)
- generatedFrame.add(btm)
- }
- uiThread {
- nextFrame()
- }
- }
+ loadUrl(url)
} else if (File(string).exists()) {
- val extractedFrame = APNGDisassembler(Loader().load(File(string))).pngList
- Frames = extractedFrame
-
- Frames.forEach {
- val btm = Bitmap.createBitmap(Frames[0].maxWidth, Frames[0].maxHeight, Bitmap.Config.ARGB_8888)
- val canvas = Canvas(btm)
- canvas.drawBitmap(BitmapFactory.decodeByteArray(it.byteArray, 0, it.byteArray.size), it.x_offsets.toFloat(), it.y_offsets.toFloat(), null)
- generatedFrame.add(btm)
- }
- nextFrame()
+ load(File(string))
}
}
- fun load(byteArray: ByteArray) {
- val extractedFrame = APNGDisassembler(byteArray).pngList
- Frames = extractedFrame
-
- Frames.forEach {
- val btm = Bitmap.createBitmap(Frames[0].maxWidth, Frames[0].maxHeight, Bitmap.Config.ARGB_8888)
- val canvas = Canvas(btm)
- canvas.drawBitmap(BitmapFactory.decodeByteArray(it.byteArray, 0, it.byteArray.size), it.x_offsets.toFloat(), it.y_offsets.toFloat(), null)
- generatedFrame.add(btm)
- }
-
- nextFrame()
- }
-
fun nextFrame() {
if (counter == Frames.size) {
counter = 0
@@ -92,8 +250,8 @@ class ApngAnimator(val imageView : ImageView) {
imageView.setImageBitmap(generatedFrame[counter])
counter++
myHandler.postDelayed({
- mustPlay()
- }, delay.toLong())
+ ifmustPlay()
+ }, delay.toLong() * speed)
}
fun pause() {
@@ -103,15 +261,17 @@ class ApngAnimator(val imageView : ImageView) {
fun play() {
if (!play) {
play = true
- mustPlay()
+ ifmustPlay()
}
}
- private fun mustPlay() {
+ private fun ifmustPlay() {
if (play) {
nextFrame()
}
}
-
+ fun setFrameSpeed(speed : Int) {
+ this.speed = speed
+ }
}
\ No newline at end of file
diff --git a/apng_library/src/main/java/oupson/apng/Frame.kt b/apng_library/src/main/java/oupson/apng/Frame.kt
index 033a506..eda9642 100644
--- a/apng_library/src/main/java/oupson/apng/Frame.kt
+++ b/apng_library/src/main/java/oupson/apng/Frame.kt
@@ -29,6 +29,9 @@ class Frame {
val maxWidth : Int
val maxHeight : Int
+ val blend_op: Utils.Companion.blend_op
+ val dispose_op : Utils.Companion.dispose_op
+
constructor(byteArray: ByteArray) {
if (isPng(byteArray)) {
this.byteArray = byteArray
@@ -50,6 +53,8 @@ class Frame {
maxHeight = -1
maxWidth = -1
+ blend_op = Utils.Companion.blend_op.APNG_BLEND_OP_SOURCE
+ dispose_op = Utils.Companion.dispose_op.APNG_DISPOSE_OP_NONE
} else {
throw NotPngException()
}
@@ -75,12 +80,14 @@ class Frame {
maxHeight = -1
maxWidth = -1
+ blend_op = Utils.Companion.blend_op.APNG_BLEND_OP_SOURCE
+ dispose_op = Utils.Companion.dispose_op.APNG_DISPOSE_OP_NONE
} else {
throw NotPngException()
}
}
- constructor(byteArray: ByteArray, delay : Float, xOffsets : Int, yOffsets : Int, maxWidth : Int, maxHeight : Int) {
+ constructor(byteArray: ByteArray, delay : Float, xOffsets : Int, yOffsets : Int, maxWidth : Int, maxHeight : Int, blend_op: Utils.Companion.blend_op, dispose_op: Utils.Companion.dispose_op) {
if (isPng(byteArray)) {
this.byteArray = byteArray
// Get width and height for image
@@ -101,6 +108,8 @@ class Frame {
this.maxWidth = maxWidth
this.maxHeight = maxHeight
+ this.blend_op = blend_op
+ this.dispose_op = dispose_op
} else {
throw NotPngException()
}
diff --git a/apng_library/src/main/java/oupson/apng/fcTL.kt b/apng_library/src/main/java/oupson/apng/fcTL.kt
index d1eea0c..8961ae8 100644
--- a/apng_library/src/main/java/oupson/apng/fcTL.kt
+++ b/apng_library/src/main/java/oupson/apng/fcTL.kt
@@ -1,5 +1,9 @@
package oupson.apng
+import android.util.Log
+import oupson.apng.Utils.Companion.getBlend_op
+import oupson.apng.Utils.Companion.getDispose_op
+
class fcTL(byteArray: ByteArray) {
private var corpsSize = -1
@@ -16,6 +20,8 @@ class fcTL(byteArray: ByteArray) {
var x_offset : Int = 0
var y_offset : Int = 0
+ var blend_op : Utils.Companion.blend_op = Utils.Companion.blend_op.APNG_BLEND_OP_SOURCE
+ var dispose_op : Utils.Companion.dispose_op= Utils.Companion.dispose_op.APNG_DISPOSE_OP_NONE
init {
for (i in 0 until byteArray.size) {
// Find fcTL chunk
@@ -91,6 +97,9 @@ class fcTL(byteArray: ByteArray) {
}
fcTLBody= _fcTLBody.toByteArray()
+ blend_op = getBlend_op(String.format("%02x", byteArray[33]).toLong(16).toInt())
+
+ dispose_op = getDispose_op(String.format("%02x", byteArray[32]).toLong(16).toInt())
}
}
}
diff --git a/app-test/src/main/java/oupson/apngcreator/MainActivity.kt b/app-test/src/main/java/oupson/apngcreator/MainActivity.kt
index 891ee9e..74ec105 100644
--- a/app-test/src/main/java/oupson/apngcreator/MainActivity.kt
+++ b/app-test/src/main/java/oupson/apngcreator/MainActivity.kt
@@ -26,7 +26,7 @@ import java.net.URL
class MainActivity : AppCompatActivity() {
lateinit var animator : ApngAnimator
- val imageUrl = "http://oupson.oupsman.fr/apng/image.apng"
+ val imageUrl = "https://cloud.githubusercontent.com/assets/13003036/24979875/e658e7c8-1fa3-11e7-908a-f1a201d38d52.png"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)