Test if optimised and non-optimised APNG are the same
This commit is contained in:
parent
f826afff86
commit
be9e5426e0
|
@ -4,11 +4,17 @@ import android.content.Context
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.AnimationDrawable
|
||||||
|
import android.graphics.drawable.BitmapDrawable
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import junit.framework.TestCase.assertFalse
|
import junit.framework.TestCase.assertFalse
|
||||||
import junit.framework.TestCase.assertTrue
|
import junit.framework.TestCase.assertTrue
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import oupson.apng.decoder.ApngDecoder
|
||||||
|
import oupson.apng.encoder.ApngEncoder
|
||||||
import oupson.apng.utils.Utils
|
import oupson.apng.utils.Utils
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
|
||||||
|
|
||||||
class ApngEncoderInstrumentedTest {
|
class ApngEncoderInstrumentedTest {
|
||||||
|
@ -38,7 +44,7 @@ class ApngEncoderInstrumentedTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun containTransparency() {
|
fun testContainTransparency() {
|
||||||
val context = InstrumentationRegistry.getInstrumentation().context
|
val context = InstrumentationRegistry.getInstrumentation().context
|
||||||
|
|
||||||
val bunnyFrame1 = getFrame(context, "bunny/frame_apngframe01.png")
|
val bunnyFrame1 = getFrame(context, "bunny/frame_apngframe01.png")
|
||||||
|
@ -48,6 +54,118 @@ class ApngEncoderInstrumentedTest {
|
||||||
assertTrue(Utils.containTransparency(ballFrame1))
|
assertTrue(Utils.containTransparency(ballFrame1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testOptimiseBall() {
|
||||||
|
val context = InstrumentationRegistry.getInstrumentation().context
|
||||||
|
val list = context.assets.list("ball")?.map { getFrame(context, "ball/$it") }!!
|
||||||
|
|
||||||
|
val optimisedOutputStream = ByteArrayOutputStream()
|
||||||
|
val optimisedEncoder = ApngEncoder(optimisedOutputStream, list[0].width, list[0].height, list.size)
|
||||||
|
.setOptimiseApng(true)
|
||||||
|
|
||||||
|
list.forEach {
|
||||||
|
optimisedEncoder.writeFrame(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
optimisedEncoder.writeEnd()
|
||||||
|
optimisedOutputStream.close()
|
||||||
|
|
||||||
|
val bytes = optimisedOutputStream.toByteArray()
|
||||||
|
val optimisedInputStream = ByteArrayInputStream(bytes)
|
||||||
|
|
||||||
|
val optimisedApng =
|
||||||
|
ApngDecoder.decodeApng(context, optimisedInputStream) as AnimationDrawable
|
||||||
|
|
||||||
|
optimisedInputStream.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
val nonOptimisedOutputStream = ByteArrayOutputStream()
|
||||||
|
|
||||||
|
val nonOptimisedEncoder = ApngEncoder(nonOptimisedOutputStream, list[0].width, list[0].height, list.size)
|
||||||
|
.setOptimiseApng(false)
|
||||||
|
|
||||||
|
list.forEach {
|
||||||
|
nonOptimisedEncoder.writeFrame(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
nonOptimisedEncoder.writeEnd()
|
||||||
|
|
||||||
|
nonOptimisedOutputStream.close()
|
||||||
|
|
||||||
|
val nonOptimisedBytes = nonOptimisedOutputStream.toByteArray()
|
||||||
|
val nonOptimisedInputStream = ByteArrayInputStream(nonOptimisedBytes)
|
||||||
|
|
||||||
|
val nonOptimisedApng =
|
||||||
|
ApngDecoder.decodeApng(context, nonOptimisedInputStream) as AnimationDrawable
|
||||||
|
nonOptimisedInputStream.close()
|
||||||
|
|
||||||
|
for (i in 0 until optimisedApng.numberOfFrames) {
|
||||||
|
assertTrue(
|
||||||
|
isBitmapSimilar(
|
||||||
|
(optimisedApng.getFrame(i) as BitmapDrawable).bitmap,
|
||||||
|
(nonOptimisedApng.getFrame(i) as BitmapDrawable).bitmap
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testOptimiseBunny() {
|
||||||
|
val context = InstrumentationRegistry.getInstrumentation().context
|
||||||
|
val list = context.assets.list("bunny")?.map { getFrame(context, "bunny/$it") }!!
|
||||||
|
|
||||||
|
val optimisedOutputStream = ByteArrayOutputStream()
|
||||||
|
val optimisedEncoder = ApngEncoder(optimisedOutputStream, list[0].width, list[0].height, list.size)
|
||||||
|
.setOptimiseApng(true)
|
||||||
|
|
||||||
|
list.forEach {
|
||||||
|
optimisedEncoder.writeFrame(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
optimisedEncoder.writeEnd()
|
||||||
|
optimisedOutputStream.close()
|
||||||
|
|
||||||
|
val bytes = optimisedOutputStream.toByteArray()
|
||||||
|
val optimisedInputStream = ByteArrayInputStream(bytes)
|
||||||
|
|
||||||
|
val optimisedApng =
|
||||||
|
ApngDecoder.decodeApng(context, optimisedInputStream) as AnimationDrawable
|
||||||
|
|
||||||
|
optimisedInputStream.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
val nonOptimisedOutputStream = ByteArrayOutputStream()
|
||||||
|
|
||||||
|
val nonOptimisedEncoder = ApngEncoder(nonOptimisedOutputStream, list[0].width, list[0].height, list.size)
|
||||||
|
.setOptimiseApng(false)
|
||||||
|
|
||||||
|
list.forEach {
|
||||||
|
nonOptimisedEncoder.writeFrame(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
nonOptimisedEncoder.writeEnd()
|
||||||
|
|
||||||
|
nonOptimisedOutputStream.close()
|
||||||
|
|
||||||
|
val nonOptimisedBytes = nonOptimisedOutputStream.toByteArray()
|
||||||
|
val nonOptimisedInputStream = ByteArrayInputStream(nonOptimisedBytes)
|
||||||
|
|
||||||
|
val nonOptimisedApng =
|
||||||
|
ApngDecoder.decodeApng(context, nonOptimisedInputStream) as AnimationDrawable
|
||||||
|
nonOptimisedInputStream.close()
|
||||||
|
|
||||||
|
for (i in 0 until optimisedApng.numberOfFrames) {
|
||||||
|
assertTrue(
|
||||||
|
isBitmapSimilar(
|
||||||
|
(optimisedApng.getFrame(i) as BitmapDrawable).bitmap,
|
||||||
|
(nonOptimisedApng.getFrame(i) as BitmapDrawable).bitmap
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun isSimilar(buffer : Bitmap, frame : Bitmap, diff : Utils.Companion.DiffResult) : Boolean {
|
private fun isSimilar(buffer : Bitmap, frame : Bitmap, diff : Utils.Companion.DiffResult) : Boolean {
|
||||||
val btm = buffer.copy(Bitmap.Config.ARGB_8888, true)
|
val btm = buffer.copy(Bitmap.Config.ARGB_8888, true)
|
||||||
|
|
||||||
|
@ -69,6 +187,17 @@ class ApngEncoderInstrumentedTest {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isBitmapSimilar(btm1 : Bitmap, btm2 : Bitmap) : Boolean {
|
||||||
|
for (y in 0 until btm1.height) {
|
||||||
|
for (x in 0 until btm1.width) {
|
||||||
|
if (btm1.getPixel(x, y) != btm2.getPixel(x, y)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
private fun getFrame(context: Context, name: String) : Bitmap {
|
private fun getFrame(context: Context, name: String) : Bitmap {
|
||||||
val inputStream = context.assets.open(name)
|
val inputStream = context.assets.open(name)
|
||||||
|
|
||||||
|
|
|
@ -284,7 +284,13 @@ class ApngEncoder(
|
||||||
) {
|
) {
|
||||||
if (currentFrame == 0) {
|
if (currentFrame == 0) {
|
||||||
if (btm.width != width || btm.height != height)
|
if (btm.width != width || btm.height != height)
|
||||||
throw InvalidFrameSizeException(btm.width, btm.height, width, height, currentFrame == 0)
|
throw InvalidFrameSizeException(
|
||||||
|
btm.width,
|
||||||
|
btm.height,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
currentFrame == 0
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
var frameBtm = btm
|
var frameBtm = btm
|
||||||
|
@ -292,10 +298,10 @@ class ApngEncoder(
|
||||||
var frameYOffsets = yOffsets
|
var frameYOffsets = yOffsets
|
||||||
var frameBlendOp = blendOp
|
var frameBlendOp = blendOp
|
||||||
|
|
||||||
if (currentFrame != 0 || (currentFrame == 0 && firstFrameInAnim)) {
|
if (optimise && currentFrame != 0 || (currentFrame == 0 && firstFrameInAnim)) {
|
||||||
if (bitmapBuffer == null && optimise) {
|
if (bitmapBuffer == null) {
|
||||||
bitmapBuffer = btm.copy(btm.config, false)
|
bitmapBuffer = btm.copy(btm.config, false)
|
||||||
} else if (optimise) {
|
} else {
|
||||||
val diff = Utils.getDiffBitmap(bitmapBuffer!!, btm)
|
val diff = Utils.getDiffBitmap(bitmapBuffer!!, btm)
|
||||||
frameBtm = diff.bitmap
|
frameBtm = diff.bitmap
|
||||||
frameXOffsets = diff.offsetX
|
frameXOffsets = diff.offsetX
|
||||||
|
@ -305,8 +311,8 @@ class ApngEncoder(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (btm.width > width || btm.height > height)
|
if (frameBtm.width > width || frameBtm.height > height)
|
||||||
throw InvalidFrameSizeException(btm.width, btm.height, width, height, currentFrame == 0)
|
throw InvalidFrameSizeException(frameBtm.width, frameBtm.height, width, height, currentFrame == 0)
|
||||||
|
|
||||||
if (firstFrameInAnim || currentFrame != 0)
|
if (firstFrameInAnim || currentFrame != 0)
|
||||||
writeFCTL(frameBtm, delay, disposeOp, frameBlendOp, frameXOffsets, frameYOffsets)
|
writeFCTL(frameBtm, delay, disposeOp, frameBlendOp, frameXOffsets, frameYOffsets)
|
||||||
|
|
Loading…
Reference in New Issue