From ef95ec2e1f0d611cc965cc6b004c6c6fc1735092 Mon Sep 17 00:00:00 2001 From: oupson Date: Sat, 12 Jan 2019 15:34:57 +0100 Subject: [PATCH] Rewrite Frame Work on optimizer --- .idea/caches/build_file_checksums.ser | Bin 596 -> 596 bytes .../src/main/java/oupson/apng/Apng.kt | 5 + .../src/main/java/oupson/apng/ApngAnimator.kt | 15 ++- .../src/main/java/oupson/apng/Frame.kt | 106 +++++++++--------- .../java/oupson/apng/ImageUtils/PngEncoder.kt | 13 +-- .../oupson/apngcreator/CreatorActivity.kt | 36 +++--- .../src/main/res/layout/activity_creator.xml | 2 +- 7 files changed, 92 insertions(+), 85 deletions(-) diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index dedb7cb6b3f5db96371b1cb8a3d00455a39548b2..b431ad30e56962303e2acc3c8b75fd56d13b9deb 100644 GIT binary patch delta 16 Ycmcb@a)o8Wbk+=~c-6HV=j>nv06Aa=z5oCK delta 16 Ycmcb@a)o8Wbk_8>;a{3I&e_2T06=;N!~g&Q diff --git a/apng_library/src/main/java/oupson/apng/Apng.kt b/apng_library/src/main/java/oupson/apng/Apng.kt index ed7d387..fbcb1af 100644 --- a/apng_library/src/main/java/oupson/apng/Apng.kt +++ b/apng_library/src/main/java/oupson/apng/Apng.kt @@ -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]) diff --git a/apng_library/src/main/java/oupson/apng/ApngAnimator.kt b/apng_library/src/main/java/oupson/apng/ApngAnimator.kt index 0c78319..23770a6 100644 --- a/apng_library/src/main/java/oupson/apng/ApngAnimator.kt +++ b/apng_library/src/main/java/oupson/apng/ApngAnimator.kt @@ -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 } /** diff --git a/apng_library/src/main/java/oupson/apng/Frame.kt b/apng_library/src/main/java/oupson/apng/Frame.kt index d990a81..25c1af6 100644 --- a/apng_library/src/main/java/oupson/apng/Frame.kt +++ b/apng_library/src/main/java/oupson/apng/Frame.kt @@ -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) + } + } + } } \ No newline at end of file diff --git a/apng_library/src/main/java/oupson/apng/ImageUtils/PngEncoder.kt b/apng_library/src/main/java/oupson/apng/ImageUtils/PngEncoder.kt index 8279043..b3526c6 100644 --- a/apng_library/src/main/java/oupson/apng/ImageUtils/PngEncoder.kt +++ b/apng_library/src/main/java/oupson/apng/ImageUtils/PngEncoder.kt @@ -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 diff --git a/app-test/src/main/java/oupson/apngcreator/CreatorActivity.kt b/app-test/src/main/java/oupson/apngcreator/CreatorActivity.kt index 686d35c..5f8d868 100644 --- a/app-test/src/main/java/oupson/apngcreator/CreatorActivity.kt +++ b/app-test/src/main/java/oupson/apngcreator/CreatorActivity.kt @@ -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() diff --git a/app-test/src/main/res/layout/activity_creator.xml b/app-test/src/main/res/layout/activity_creator.xml index f879276..bcd986f 100644 --- a/app-test/src/main/res/layout/activity_creator.xml +++ b/app-test/src/main/res/layout/activity_creator.xml @@ -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" />