From 338a875b9c2e320e35f67a0f80106a721a69fa68 Mon Sep 17 00:00:00 2001 From: Oupson Date: Sat, 6 Feb 2021 17:20:10 +0100 Subject: [PATCH] Optimise APNG --- .../apng/ApngEncoderInstrumentedTest.kt | 2 ++ .../src/main/java/oupson/apng/Apng.kt | 2 +- .../src/main/java/oupson/apng/ApngAnimator.kt | 3 +-- .../src/main/java/oupson/apng/Loader.kt | 1 - .../java/oupson/apng/encoder/ApngEncoder.kt | 22 +++++++++++++++++-- .../oupson/apng/exceptions/customException.kt | 3 +++ .../src/main/java/oupson/apng/utils/Utils.kt | 10 +++++---- 7 files changed, 33 insertions(+), 10 deletions(-) diff --git a/apng_library/src/androidTest/java/oupson/apng/ApngEncoderInstrumentedTest.kt b/apng_library/src/androidTest/java/oupson/apng/ApngEncoderInstrumentedTest.kt index 78d3ab2..81b88b2 100644 --- a/apng_library/src/androidTest/java/oupson/apng/ApngEncoderInstrumentedTest.kt +++ b/apng_library/src/androidTest/java/oupson/apng/ApngEncoderInstrumentedTest.kt @@ -12,6 +12,8 @@ import oupson.apng.utils.Utils class ApngEncoderInstrumentedTest { + // TODO TEST IF OPTIMISED ANIMATIONS AND NON-OPTIMISED ANIMATIONS ARE THE SAME + @Test fun testDiffBunny() { val context = InstrumentationRegistry.getInstrumentation().context diff --git a/apng_library/src/main/java/oupson/apng/Apng.kt b/apng_library/src/main/java/oupson/apng/Apng.kt index 285babf..6f6620a 100644 --- a/apng_library/src/main/java/oupson/apng/Apng.kt +++ b/apng_library/src/main/java/oupson/apng/Apng.kt @@ -16,7 +16,7 @@ import java.io.File import java.util.zip.CRC32 -// TODO CREATE A BETTER CLASS +// TODO REMOVE /** * Create an APNG file * If you want to create an APNG, use ApngEncoder instead diff --git a/apng_library/src/main/java/oupson/apng/ApngAnimator.kt b/apng_library/src/main/java/oupson/apng/ApngAnimator.kt index 174f3bb..1a98b61 100644 --- a/apng_library/src/main/java/oupson/apng/ApngAnimator.kt +++ b/apng_library/src/main/java/oupson/apng/ApngAnimator.kt @@ -19,8 +19,7 @@ import oupson.apng.utils.Utils.Companion.isPng import java.io.File import java.net.URL -// TODO REWRITE WITH CALLBACKS -// TODO REWRITE +// TODO REMOVE /** * Class to play APNG diff --git a/apng_library/src/main/java/oupson/apng/Loader.kt b/apng_library/src/main/java/oupson/apng/Loader.kt index 0f2d25d..99a8425 100644 --- a/apng_library/src/main/java/oupson/apng/Loader.kt +++ b/apng_library/src/main/java/oupson/apng/Loader.kt @@ -8,7 +8,6 @@ import java.io.IOException import java.net.HttpURLConnection import java.net.URL -// TODO DOCUMENTATION (MAYBE WIKI) FOR THE CACHE class Loader { companion object { /** diff --git a/apng_library/src/main/java/oupson/apng/encoder/ApngEncoder.kt b/apng_library/src/main/java/oupson/apng/encoder/ApngEncoder.kt index 49e6e40..0f1bbca 100644 --- a/apng_library/src/main/java/oupson/apng/encoder/ApngEncoder.kt +++ b/apng_library/src/main/java/oupson/apng/encoder/ApngEncoder.kt @@ -245,12 +245,30 @@ class ApngEncoder( throw InvalidFrameSizeException(btm.width, btm.height, width, height, currentFrame == 0) } + var frameBtm = btm + var frameXOffsets = xOffsets + var frameYOffsets = yOffsets + var frameBlendOp = blendOp + + if (currentFrame != 0 || (currentFrame == 0 && firstFrameInAnim)) { + if (bitmapBuffer == null && optimise) { + bitmapBuffer = btm.copy(btm.config, false) + } else if (optimise) { + val diff = Utils.getDiffBitmap(bitmapBuffer!!, btm) + frameBtm = diff.bitmap + frameXOffsets = diff.offsetX + frameYOffsets = diff.offsetY + frameBlendOp = diff.blendOp + bitmapBuffer = btm.copy(btm.config, false) + } + } + if (btm.width > width || btm.height > height) throw InvalidFrameSizeException(btm.width, btm.height, width, height, currentFrame == 0) if (firstFrameInAnim || currentFrame != 0) - writeFCTL(btm, delay, disposeOp, blendOp, xOffsets, yOffsets) - writeImageData(btm) + writeFCTL(frameBtm, delay, disposeOp, frameBlendOp, frameXOffsets, frameYOffsets) + writeImageData(frameBtm) currentFrame++ } diff --git a/apng_library/src/main/java/oupson/apng/exceptions/customException.kt b/apng_library/src/main/java/oupson/apng/exceptions/customException.kt index 0efe032..4954094 100644 --- a/apng_library/src/main/java/oupson/apng/exceptions/customException.kt +++ b/apng_library/src/main/java/oupson/apng/exceptions/customException.kt @@ -26,5 +26,8 @@ class InvalidFrameSizeException(animationWidth : Int, animationHeight : Int, fra "Unknown problem" } } +} +class BadFrameDiffSize(firstFrameWidth : Int, firstFrameHeight : Int, secondFrameWidth : Int, secondFrameHeight : Int) : Exception() { + override val message: String = "${firstFrameWidth}x${firstFrameHeight} must be smaller than ${secondFrameWidth}x${secondFrameHeight}" } \ No newline at end of file diff --git a/apng_library/src/main/java/oupson/apng/utils/Utils.kt b/apng_library/src/main/java/oupson/apng/utils/Utils.kt index 647fe15..c67ad4d 100644 --- a/apng_library/src/main/java/oupson/apng/utils/Utils.kt +++ b/apng_library/src/main/java/oupson/apng/utils/Utils.kt @@ -2,6 +2,7 @@ package oupson.apng.utils import android.graphics.Bitmap import android.graphics.Color +import oupson.apng.exceptions.BadFrameDiffSize import oupson.apng.utils.Utils.Companion.BlendOp.APNG_BLEND_OP_OVER import oupson.apng.utils.Utils.Companion.BlendOp.APNG_BLEND_OP_SOURCE import oupson.apng.utils.Utils.Companion.DisposeOp.* @@ -224,12 +225,13 @@ class Utils { * @param secondBitmap A [Bitmap], a second bitmap * @return [DiffResult], the difference between the second and the first bitmap */ + @Throws(BadFrameDiffSize::class) fun getDiffBitmap(firstBitmap : Bitmap, secondBitmap : Bitmap) : DiffResult { if (firstBitmap.width < secondBitmap.width || firstBitmap.height < secondBitmap.height) { - TODO("EXCEPTION BAD IMAGE SIZE") + throw BadFrameDiffSize(firstBitmap.width, firstBitmap.height, firstBitmap.width, firstBitmap.height) } - var resultBtm = Bitmap.createBitmap(secondBitmap.width, secondBitmap.height, Bitmap.Config.ARGB_8888) + val resultBtm = Bitmap.createBitmap(secondBitmap.width, secondBitmap.height, Bitmap.Config.ARGB_8888) var offsetX = resultBtm.width + 1 var offsetY = resultBtm.height + 1 @@ -269,9 +271,9 @@ class Utils { val newHeight = lastY - offsetY // Resize bitmap - resultBtm = Bitmap.createBitmap(resultBtm, offsetX, offsetY, newWidth, newHeight) + val resizedResultBtm = Bitmap.createBitmap(resultBtm, offsetX, offsetY, newWidth, newHeight) - return DiffResult(resultBtm, offsetX, offsetY, blendOp) + return DiffResult(resizedResultBtm, offsetX, offsetY, blendOp) } /**