Skip to content

Commit

Permalink
Add chunk interface
Browse files Browse the repository at this point in the history
Prepare for release
  • Loading branch information
oupson committed Dec 8, 2018
1 parent cefb4ca commit 08d5d30
Show file tree
Hide file tree
Showing 14 changed files with 88 additions and 201 deletions.
Binary file modified .idea/caches/build_file_checksums.ser
Binary file not shown.
2 changes: 1 addition & 1 deletion apng_library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ android {
compileSdkVersion 27
defaultConfig {
minSdkVersion 21
targetSdkVersion 26
targetSdkVersion 27
versionCode 1
versionName "1.0.8"

Expand Down
38 changes: 15 additions & 23 deletions apng_library/src/main/java/oupson/apng/APNGDisassembler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import oupson.apng.chunks.fcTL
import oupson.apng.exceptions.NotApngException
import oupson.apng.utils.Utils
import oupson.apng.utils.Utils.Companion.isApng
import oupson.apng.utils.Utils.Companion.parseLength
import oupson.apng.utils.Utils.Companion.pngSignature
import oupson.apng.utils.Utils.Companion.to4Bytes
import java.util.*
Expand All @@ -24,12 +25,17 @@ class APNGDisassembler {
private var maxHeight = 0
private var blend_op: Utils.Companion.blend_op = Utils.Companion.blend_op.APNG_BLEND_OP_SOURCE
private var dispose_op: Utils.Companion.dispose_op = Utils.Companion.dispose_op.APNG_DISPOSE_OP_NONE
var apng: Apng = Apng()
private val ihdr = IHDR()

var apng: Apng = Apng()
/**
* Disassemble an Apng file
* @param byteArray The Byte Array of the file
* @return The apng decoded
*/
fun disassemble(byteArray: ByteArray) : Apng {
if (isApng(byteArray)) {
apng = Apng()
ihdr.parseIHDR(byteArray)
ihdr.parse(byteArray)
maxWidth = ihdr.pngWidth
maxHeight = ihdr.pngHeight
var cursor = 8
Expand All @@ -44,28 +50,20 @@ class APNGDisassembler {
}
}

private fun parseLength(byteArray: ByteArray) : Int {
var lengthString = ""
byteArray.forEach {
lengthString += String.format("%02x", it)
}
return lengthString.toLong(16).toInt()
}

private fun generateIhdr(ihdrOfApng: IHDR, width : Int, height : Int) : ByteArray {
val ihdr = ArrayList<Byte>()
// We need a body var to know body length and generate crc
val ihdrBody = ArrayList<Byte>()
// Add chunk body length
ihdr.addAll(to4Bytes(ihdrOfApng.ihdrCorps.size).toList())
ihdr.addAll(to4Bytes(ihdrOfApng.body.size).toList())
// Add IHDR
ihdrBody.addAll(byteArrayOf(0x49.toByte(), 0x48.toByte(), 0x44.toByte(), 0x52.toByte()).toList())
// Add the max width and height
ihdrBody.addAll(to4Bytes(width).toList())
ihdrBody.addAll(to4Bytes(height).toList())
// Add complicated stuff like depth color ...
// If you want correct png you need same parameters. Good solution is to create new png.
ihdrBody.addAll(ihdrOfApng.ihdrCorps.copyOfRange(8, 13).toList())
ihdrBody.addAll(ihdrOfApng.body.copyOfRange(8, 13).toList())
// Generate CRC
val crC32 = CRC32()
crC32.update(ihdrBody.toByteArray(), 0, ihdrBody.size)
Expand All @@ -91,9 +89,9 @@ class APNGDisassembler {
it.addAll(to4Bytes(crC32.value.toInt()).toList())
apng.cover = BitmapFactory.decodeByteArray(it.toByteArray(), 0, it.size)
}

png = ArrayList()
val fcTL = fcTL(byteArray)
val fcTL = fcTL()
fcTL.parse(byteArray)
delay = fcTL.delay
yOffset = fcTL.y_offset
xOffset = fcTL.x_offset
Expand All @@ -103,11 +101,9 @@ class APNGDisassembler {
val height = fcTL.pngHeight
png!!.addAll(pngSignature.toList())
png!!.addAll(generateIhdr(ihdr, width, height).toList())

plte?.let {
png!!.addAll(it.toList())
}

tnrs?.let {
png!!.addAll(it.toList())
}
Expand All @@ -122,15 +118,12 @@ class APNGDisassembler {
png!!.addAll(iend.toList())
png!!.addAll(to4Bytes(crC32.value.toInt()).toList())
apng.frames.add(Frame(png!!.toByteArray(), delay, xOffset, yOffset, maxWidth, maxHeight, blend_op, dispose_op))

png = ArrayList()

val fcTL = fcTL(byteArray)
val fcTL = fcTL()
fcTL.parse(byteArray)
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
Expand All @@ -140,7 +133,6 @@ class APNGDisassembler {
plte?.let {
png!!.addAll(it.toList())
}

tnrs?.let {
png!!.addAll(it.toList())
}
Expand Down
8 changes: 3 additions & 5 deletions apng_library/src/main/java/oupson/apng/Apng.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,10 @@ import oupson.apng.utils.Utils.Companion.to4Bytes
import oupson.apng.utils.Utils.Companion.toByteArray
import java.util.zip.CRC32


/**
* Create an APNG file
*/
class Apng {

var maxWidth : Int? = null
var maxHeight : Int? = null

Expand Down Expand Up @@ -226,7 +224,7 @@ class Apng {
// Add cover image : Not part of animation
// region IDAT
val idat = IDAT()
idat.parseIDAT(toByteArray(cover!!))
idat.parse(toByteArray(cover!!))
idat.IDATBody.forEach {
val idatByteArray = ArrayList<Byte>()
framesByte.addAll(to4Bytes(it.size).toList())
Expand Down Expand Up @@ -427,7 +425,7 @@ class Apng {
}

// Add chunk body length
ihdr.addAll(to4Bytes(frames[0].ihdr.ihdrCorps.size).toList())
ihdr.addAll(to4Bytes(frames[0].ihdr.body.size).toList())
// Add IHDR
ihdr_body.addAll(byteArrayOf(0x49.toByte(), 0x48.toByte(), 0x44.toByte(), 0x52.toByte()).toList())

Expand All @@ -437,7 +435,7 @@ class Apng {

// Add complicated stuff like depth color ...
// If you want correct png you need same parameters. Good solution is to create new png.
ihdr_body.addAll(frames[0].ihdr.ihdrCorps.copyOfRange(8, 13).toList())
ihdr_body.addAll(frames[0].ihdr.body.copyOfRange(8, 13).toList())

// Generate CRC
val crC32 = CRC32()
Expand Down
10 changes: 7 additions & 3 deletions apng_library/src/main/java/oupson/apng/ApngAnimator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,14 @@ class ApngAnimator(private val context: Context) {
private var anim: CustomAnimationDrawable? = null
private var activeAnimation: CustomAnimationDrawable? = null
private var doOnLoaded : (ApngAnimator) -> Unit = {}
@SuppressWarnings("WeakerAccess")
private var AnimationLoopListener : () -> Unit = {}
private var duration : ArrayList<Float>? = null
private var scaleType : ImageView.ScaleType? = null

var isApng = false
@SuppressWarnings("WeakerAccess")
var loadNotApng = true

private val sharedPreferences : SharedPreferences = context.getSharedPreferences("apngAnimator", Context.MODE_PRIVATE)

init {
Expand All @@ -54,6 +56,7 @@ class ApngAnimator(private val context: Context) {
/**
* Specify if the library could load non apng file
*/
@SuppressWarnings("WeakerAccess")
fun loadNotApng(boolean: Boolean) {
val editor = sharedPreferences.edit()
editor.putBoolean("loadNotApng", boolean)
Expand All @@ -75,7 +78,7 @@ class ApngAnimator(private val context: Context) {
* @param speed The speed
* @throws NotApngException
*/
@JvmOverloads
@SuppressWarnings("WeakerAccess")
fun load(file: File, speed: Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) {
doAsync {
val bytes = file.readBytes()
Expand Down Expand Up @@ -140,6 +143,7 @@ class ApngAnimator(private val context: Context) {
* @param speed The speed
* @throws NotApngException
*/
@SuppressWarnings("WeakerAccess")
fun loadUrl(url: URL, speed: Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) {
doAsync(exceptionHandler = { e -> e.printStackTrace() }) {
this@ApngAnimator.speed = speed
Expand Down Expand Up @@ -171,13 +175,13 @@ class ApngAnimator(private val context: Context) {
}
}


/**
* Load an APNG file and starts playing the animation.
* @param byteArray ByteArray of the file
* @param speed The speed
* @throws NotApngException
*/
@SuppressWarnings("WeakerAccess")
fun load(byteArray: ByteArray, speed: Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) {
doAsync {
this@ApngAnimator.speed = speed
Expand Down
20 changes: 10 additions & 10 deletions apng_library/src/main/java/oupson/apng/Frame.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ class Frame {
this.byteArray = bytes
// Get width and height for image
ihdr = IHDR()
ihdr.parseIHDR(bytes)
ihdr.parse(bytes)

width = ihdr.pngWidth
height = ihdr.pngHeight

// Get IDAT Bytes
idat = IDAT()
idat.parseIDAT(bytes)
idat.parse(bytes)

delay = 1000f

Expand All @@ -69,14 +69,14 @@ class Frame {
this.byteArray = bytes
// Get width and height for image
ihdr = IHDR()
ihdr.parseIHDR(bytes)
ihdr.parse(bytes)

width = ihdr.pngWidth
height = ihdr.pngHeight

// Get IDAT Bytes
idat = IDAT()
idat.parseIDAT(bytes)
idat.parse(bytes)

this.delay = delay
blend_op = Utils.Companion.blend_op.APNG_BLEND_OP_SOURCE
Expand All @@ -93,14 +93,14 @@ class Frame {
this.byteArray = bytes
// Get width and height for image
ihdr = IHDR()
ihdr.parseIHDR(bytes)
ihdr.parse(bytes)

width = ihdr.pngWidth
height = ihdr.pngHeight

// Get IDAT Bytes
idat = IDAT()
idat.parseIDAT(bytes)
idat.parse(bytes)

this.delay = delay

Expand All @@ -121,14 +121,14 @@ class Frame {
this.byteArray = bytes
// Get width and height for image
ihdr = IHDR()
ihdr.parseIHDR(bytes)
ihdr.parse(bytes)

width = ihdr.pngWidth
height = ihdr.pngHeight

// Get IDAT Bytes
idat = IDAT()
idat.parseIDAT(bytes)
idat.parse(bytes)

this.delay = delay

Expand All @@ -149,14 +149,14 @@ class Frame {
this.byteArray = byteArray
// Get width and height for image
ihdr = IHDR()
ihdr.parseIHDR(byteArray)
ihdr.parse(byteArray)

width = ihdr.pngWidth
height = ihdr.pngHeight

// Get IDAT Bytes
idat = IDAT()
idat.parseIDAT(byteArray)
idat.parse(byteArray)

this.delay = delay

Expand Down
6 changes: 6 additions & 0 deletions apng_library/src/main/java/oupson/apng/Loader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ import java.net.URL

class Loader {
companion object {
/**
* Download file from given url
* @param context Context of app
* @param url Url of the file to download
* @return [ByteArray] of the file
*/
@Throws(IOException::class)
fun load(context: Context, url: URL): ByteArray {
val currentDir = context.filesDir
Expand Down
6 changes: 6 additions & 0 deletions apng_library/src/main/java/oupson/apng/chunks/Chunk.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package oupson.apng.chunks

interface Chunk {
var body : ByteArray
fun parse(byteArray: ByteArray)
}
24 changes: 7 additions & 17 deletions apng_library/src/main/java/oupson/apng/chunks/IDAT.kt
Original file line number Diff line number Diff line change
@@ -1,30 +1,20 @@
package oupson.apng.chunks

class IDAT {
private var bodySize = -1
import oupson.apng.utils.Utils.Companion.parseLength

class IDAT : Chunk {
var IDATBody: ArrayList<ByteArray> = ArrayList()
override var body = byteArrayOf()

fun parseIDAT(byteArray: ByteArray) {
override fun parse(byteArray: ByteArray) {
for (i in 0 until byteArray.size) {
// Find IDAT chunk
if (byteArray[i] == 0x49.toByte() && byteArray[i + 1] == 0x44.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)
}
bodySize = lengthString.toLong(16).toInt()

val bodySize = parseLength(byteArray.copyOfRange(i - 4, i))
// Get image bytes
val _IDATbody = ArrayList<Byte>()
for (j in i +4 until i + 4 + bodySize) {
_IDATbody.add(byteArray[j])
}
IDATBody.add(_IDATbody.toByteArray())
IDATBody.add(byteArray.copyOfRange(i + 4, i + 4 + bodySize))
}
}

}

}
Loading

0 comments on commit 08d5d30

Please sign in to comment.