Rewrite Frame

Work on optimizer
This commit is contained in:
oupson 2019-01-12 15:34:57 +01:00
parent 6d1f6af7c5
commit ef95ec2e1f
7 changed files with 92 additions and 85 deletions

View File

@ -2,6 +2,7 @@ package oupson.apng
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Environment
import oupson.apng.ImageUtils.BitmapDiffCalculator
import oupson.apng.ImageUtils.PngEncoder
import oupson.apng.ImageUtils.PnnQuantizer
@ -13,6 +14,7 @@ import oupson.apng.utils.Utils.Companion.getDispose_op
import oupson.apng.utils.Utils.Companion.pngSignature
import oupson.apng.utils.Utils.Companion.to2Bytes
import oupson.apng.utils.Utils.Companion.to4Bytes
import java.io.File
import java.util.zip.CRC32
/**
@ -517,6 +519,9 @@ class Apng {
it.maxWidth = maxWidth
it.maxHeight = maxHeight
}
for (i in 0 until frames.size){
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "frameCreated$i.png").writeBytes(frames[i].byteArray)
}
val drawedFrame = ApngAnimator(null).draw(frames)
for (i in 1 until frames.size) {
val diffCalculator = BitmapDiffCalculator(drawedFrame[i - 1], drawedFrame[i])

View File

@ -79,7 +79,7 @@ class ApngAnimator(private val context: Context?) {
* @throws NotApngException
*/
@SuppressWarnings("WeakerAccess")
fun load(file: File, speed: Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) {
fun load(file: File, speed: Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) : ApngAnimator {
doAsync {
val bytes = file.readBytes()
if (isApng(bytes)) {
@ -103,6 +103,7 @@ class ApngAnimator(private val context: Context?) {
}
}
}
return this
}
@ -113,7 +114,7 @@ class ApngAnimator(private val context: Context?) {
* @param speed The speed
* @throws NotApngException
*/
fun load(uri : Uri, speed: Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) {
fun load(uri : Uri, speed: Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) : ApngAnimator {
doAsync {
context?.contentResolver?.openInputStream(uri)?.readBytes()?.let {
if (isApng(it)) {
@ -138,6 +139,7 @@ class ApngAnimator(private val context: Context?) {
}
}
}
return this
}
/**
@ -147,7 +149,7 @@ class ApngAnimator(private val context: Context?) {
* @throws NotApngException
*/
@SuppressWarnings("WeakerAccess")
fun loadUrl(url: URL, speed: Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) {
fun loadUrl(url: URL, speed: Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) : ApngAnimator {
doAsync(exceptionHandler = { e -> e.printStackTrace() }) {
this@ApngAnimator.speed = speed
// Download PNG
@ -176,6 +178,7 @@ class ApngAnimator(private val context: Context?) {
}
return this
}
/**
@ -185,7 +188,7 @@ class ApngAnimator(private val context: Context?) {
* @throws NotApngException
*/
@SuppressWarnings("WeakerAccess")
fun load(byteArray: ByteArray, speed: Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) {
fun load(byteArray: ByteArray, speed: Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) : ApngAnimator {
doAsync {
this@ApngAnimator.speed = speed
if (isApng(byteArray)) {
@ -209,6 +212,7 @@ class ApngAnimator(private val context: Context?) {
}
}
}
return this
}
/**
@ -217,7 +221,7 @@ class ApngAnimator(private val context: Context?) {
* @param speed The speed
* @throws NotApngException
*/
fun load(string: String, speed : Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) {
fun load(string: String, speed : Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) : ApngAnimator {
doAsync {
this@ApngAnimator.speed = speed
if (string.contains("http") || string.contains("https")) {
@ -240,6 +244,7 @@ class ApngAnimator(private val context: Context?) {
}
}
}
return this
}
/**

View File

@ -1,10 +1,14 @@
package oupson.apng
import android.util.Log
import oupson.apng.chunks.IDAT
import oupson.apng.chunks.IHDR
import oupson.apng.exceptions.NotPngException
import oupson.apng.utils.Utils
import oupson.apng.utils.Utils.Companion.IDAT
import oupson.apng.utils.Utils.Companion.IHDR
import oupson.apng.utils.Utils.Companion.isPng
import java.util.*
/**
* A frame for an animated png
@ -18,12 +22,12 @@ class Frame {
var byteArray : ByteArray
var width : Int
var height : Int
var width : Int = -1
var height : Int = -1
var ihdr : IHDR
lateinit var ihdr : IHDR
var idat : IDAT
lateinit var idat : IDAT
val delay : Float
@ -39,21 +43,17 @@ class Frame {
constructor(byteArray: ByteArray) {
if (isPng(byteArray)) {
this.byteArray = byteArray
Log.e("tag", byteArray.size.toString())
// Get width and height for image
ihdr = IHDR()
ihdr.parse(byteArray)
width = ihdr.pngWidth
height = ihdr.pngHeight
// Get IDAT Bytes
idat = IDAT()
idat.parse(byteArray)
delay = 1000f
blend_op = Utils.Companion.blend_op.APNG_BLEND_OP_SOURCE
dispose_op = Utils.Companion.dispose_op.APNG_DISPOSE_OP_NONE
var cursor = 8
while (cursor < byteArray.size) {
val chunk = byteArray.copyOfRange(cursor, cursor + Utils.parseLength(byteArray.copyOfRange(cursor, cursor + 4)) + 12)
parseChunk(chunk)
cursor += Utils.parseLength(byteArray.copyOfRange(cursor, cursor + 4)) + 12
}
} else {
throw NotPngException()
}
@ -62,15 +62,12 @@ class Frame {
if (isPng(byteArray)) {
this.byteArray = byteArray
// Get width and height for image
ihdr = IHDR()
ihdr.parse(byteArray)
width = ihdr.pngWidth
height = ihdr.pngHeight
// Get IDAT Bytes
idat = IDAT()
idat.parse(byteArray)
var cursor = 8
while (cursor < byteArray.size) {
val chunk = byteArray.copyOfRange(cursor, cursor + Utils.parseLength(byteArray.copyOfRange(cursor, cursor + 4)) + 12)
parseChunk(chunk)
cursor += Utils.parseLength(byteArray.copyOfRange(cursor, cursor + 4)) + 12
}
this.delay = delay
blend_op = Utils.Companion.blend_op.APNG_BLEND_OP_SOURCE
@ -84,15 +81,12 @@ class Frame {
if (isPng(byteArray)) {
this.byteArray = byteArray
// Get width and height for image
ihdr = IHDR()
ihdr.parse(byteArray)
width = ihdr.pngWidth
height = ihdr.pngHeight
// Get IDAT Bytes
idat = IDAT()
idat.parse(byteArray)
var cursor = 8
while (cursor < byteArray.size) {
val chunk = byteArray.copyOfRange(cursor, cursor + Utils.parseLength(byteArray.copyOfRange(cursor, cursor + 4)) + 12)
parseChunk(chunk)
cursor += Utils.parseLength(byteArray.copyOfRange(cursor, cursor + 4)) + 12
}
this.delay = delay
@ -110,15 +104,12 @@ class Frame {
if (isPng(byteArray)) {
this.byteArray = byteArray
// Get width and height for image
ihdr = IHDR()
ihdr.parse(byteArray)
width = ihdr.pngWidth
height = ihdr.pngHeight
// Get IDAT Bytes
idat = IDAT()
idat.parse(byteArray)
var cursor = 8
while (cursor < byteArray.size) {
val chunk = byteArray.copyOfRange(cursor, cursor + Utils.parseLength(byteArray.copyOfRange(cursor, cursor + 4)) + 12)
parseChunk(chunk)
cursor += Utils.parseLength(byteArray.copyOfRange(cursor, cursor + 4)) + 12
}
this.delay = delay
@ -138,15 +129,12 @@ class Frame {
if (isPng(byteArray)) {
this.byteArray = byteArray
// Get width and height for image
ihdr = IHDR()
ihdr.parse(byteArray)
width = ihdr.pngWidth
height = ihdr.pngHeight
// Get IDAT Bytes
idat = IDAT()
idat.parse(byteArray)
var cursor = 8
while (cursor < byteArray.size) {
val chunk = byteArray.copyOfRange(cursor, cursor + Utils.parseLength(byteArray.copyOfRange(cursor, cursor + 4)) + 12)
parseChunk(chunk)
cursor += Utils.parseLength(byteArray.copyOfRange(cursor, cursor + 4)) + 12
}
this.delay = delay
@ -161,4 +149,20 @@ class Frame {
throw NotPngException()
}
}
fun parseChunk(byteArray: ByteArray) {
when(Arrays.toString(byteArray.copyOfRange(4, 8))) {
IHDR -> {
ihdr = IHDR()
ihdr.parse(byteArray)
width = ihdr.pngWidth
height = ihdr.pngHeight
}
IDAT -> {
// Get IDAT Bytes
idat = IDAT()
idat.parse(byteArray)
}
}
}
}

View File

@ -80,22 +80,22 @@ class PngEncoder {
* @param compressionLevel ! Don't use it : It's buggy
*/
fun encode(image: Bitmap, encodeAlpha: Boolean = false, filter: Int = 0, compressionLevel: Int = 0): ByteArray {
Companion.filter = FILTER_NONE
this.filter = FILTER_NONE
if (filter <= FILTER_LAST) {
Companion.filter = filter
this.filter = filter
}
if (compressionLevel in 0..9) {
Companion.compressionLevel = compressionLevel
this.compressionLevel = compressionLevel
}
Companion.encodeAlpha = encodeAlpha
this.encodeAlpha = encodeAlpha
val pngIdBytes = byteArrayOf(-119, 80, 78, 71, 13, 10, 26, 10)
width = image.width
height = image.height
Companion.image = image
this.image = image
/*
* start with an array that is big enough to hold all the pixels
* (plus filter bytes), and an extra 200 bytes for header info
@ -221,9 +221,8 @@ class PngEncoder {
* Write a PNG "IHDR" chunk into the pngBytes array.
*/
private fun writeHeader() {
val startPos: Int = bytePos
bytePos = writeInt4(13, bytePos)
val startPos: Int = bytePos
bytePos = writeBytes(IHDR, bytePos)
width = image!!.width
height = image!!.height

View File

@ -4,11 +4,9 @@ import android.app.Activity
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.os.Bundle
import android.os.Environment
import android.support.v7.app.AppCompatActivity
import android.util.Log
import kotlinx.android.synthetic.main.activity_creator.*
import org.jetbrains.anko.alert
import org.jetbrains.anko.customView
@ -17,7 +15,6 @@ import org.jetbrains.anko.sdk27.coroutines.onClick
import oupson.apng.APNGDisassembler
import oupson.apng.Apng
import oupson.apng.ApngAnimator
import oupson.apng.ImageUtils.PngEncoder
import oupson.apngcreator.adapter.frameListViewAdapter
import java.io.File
@ -45,33 +42,30 @@ class CreatorActivity : AppCompatActivity() {
fab_create.onClick {
var apngCreated = Apng()
items.forEach {
apngCreated.addFrames(it)
items.forEach { bitmap ->
apngCreated.addFrames(bitmap)
}
Log.e("tag", apngCreated.frames.size.toString())
apngCreated = APNGDisassembler.disassemble(apngCreated.toByteArray())
apngCreated.optimiseFrame()
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "vtm").writeBytes(apngCreated.toByteArray())
apngCreated = APNGDisassembler.disassemble(apngCreated.toByteArray()).apply {
optimiseFrame()
}
val a = ApngAnimator(applicationContext)
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "apn.png").writeBytes(apngCreated.toByteArray())
a.load(apngCreated.toByteArray())
a.onLoaded {
alert {
a.onLoaded { anim ->
alert {
customView {
imageView {
Log.e("tag", "${it.anim?.numberOfFrames.toString()} : ${items.size}")
it.anim?.let {
for (i in 0 until it.numberOfFrames) {
val vt = Bitmap.createBitmap(it.getFrame(i).intrinsicWidth, it.getFrame(i).intrinsicHeight, Bitmap.Config.ARGB_8888)
/**anim.anim?.let {cu ->
for (i in 0 until cu.numberOfFrames) {
val vt = Bitmap.createBitmap(cu.getFrame(i).intrinsicWidth, cu.getFrame(i).intrinsicHeight, Bitmap.Config.ARGB_8888)
val canvas = Canvas(vt)
it.getFrame(i).draw(canvas)
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "frame$i.png").writeBytes(PngEncoder.encode(vt))
cu.getFrame(i).draw(canvas)
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "frameCreated$i.png").writeBytes(PngEncoder.encode(vt))
}
}
this.setImageDrawable(it.anim)
this.setImageDrawable(anim.anim)
*/
}
}
}.show()

View File

@ -26,7 +26,7 @@
android:clickable="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="@drawable/ic_play_arrow_white_24dp" />
app:srcCompat="@drawable/ic_add_white_24dp" />
<ListView
android:id="@+id/dragView"