Bitmap Diff + Instrumented tests
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 187 KiB |
After Width: | Height: | Size: 174 KiB |
After Width: | Height: | Size: 183 KiB |
After Width: | Height: | Size: 188 KiB |
After Width: | Height: | Size: 188 KiB |
After Width: | Height: | Size: 176 KiB |
After Width: | Height: | Size: 178 KiB |
After Width: | Height: | Size: 178 KiB |
After Width: | Height: | Size: 184 KiB |
After Width: | Height: | Size: 173 KiB |
After Width: | Height: | Size: 175 KiB |
After Width: | Height: | Size: 181 KiB |
After Width: | Height: | Size: 166 KiB |
After Width: | Height: | Size: 172 KiB |
After Width: | Height: | Size: 173 KiB |
After Width: | Height: | Size: 172 KiB |
|
@ -0,0 +1,57 @@
|
|||
package oupson.apng
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Color
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import junit.framework.TestCase.assertTrue
|
||||
import org.junit.Test
|
||||
import oupson.apng.encoder.ApngEncoder
|
||||
|
||||
|
||||
class ApngEncoderInstrumentedTest {
|
||||
@Test
|
||||
fun testDiff() { // TODO BLEND / DISPOSE OP
|
||||
val context = InstrumentationRegistry.getInstrumentation().context
|
||||
|
||||
val frame1 = getFrame(context, "bunny/frame_apngframe01.png")
|
||||
val frame2 = getFrame(context, "bunny/frame_apngframe02.png")
|
||||
|
||||
val diff = ApngEncoder.getDiffBitmap(frame1, frame2)
|
||||
|
||||
assertTrue(isSimilar(frame1, frame2, diff))
|
||||
}
|
||||
|
||||
private fun isSimilar(buffer : Bitmap, frame : Bitmap, diff : Triple<Bitmap, Int, Int>) : Boolean {
|
||||
val btm = buffer.copy(Bitmap.Config.ARGB_8888, true)
|
||||
|
||||
for (y in 0 until diff.first.height) {
|
||||
for (x in 0 until diff.first.width) {
|
||||
val p = diff.first.getPixel(x, y)
|
||||
if (p != Color.TRANSPARENT)
|
||||
btm.setPixel(diff.second + x, diff.third + y, p)
|
||||
}
|
||||
}
|
||||
|
||||
for (y in 0 until buffer.height) {
|
||||
for (x in 0 until buffer.width) {
|
||||
if (frame.getPixel(x, y) != btm.getPixel(x, y)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun getFrame(context: Context, name: String) : Bitmap {
|
||||
val inputStream = context.assets.open(name)
|
||||
|
||||
val bitmap = BitmapFactory.decodeStream(inputStream, null, BitmapFactory.Options().apply {
|
||||
inPreferredConfig = Bitmap.Config.ARGB_8888
|
||||
})
|
||||
|
||||
inputStream.close()
|
||||
return bitmap!!
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package oupson.apng;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
||||
|
||||
assertEquals("oupson.apng.test", appContext.getPackageName());
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ package oupson.apng.encoder
|
|||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Color
|
||||
import android.util.Log
|
||||
import oupson.apng.exceptions.InvalidFrameSizeException
|
||||
import oupson.apng.utils.Utils
|
||||
|
@ -51,6 +52,51 @@ class ApngEncoder(
|
|||
|
||||
/** Constants for filter (LAST) */
|
||||
const val FILTER_LAST = 2
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
fun getDiffBitmap(bitmapBuffer : Bitmap, btm : Bitmap) : Triple<Bitmap, Int, Int> { // TODO BLEND / DISPOSE OP
|
||||
if (bitmapBuffer.width < btm.width || bitmapBuffer.height < btm.height) {
|
||||
TODO("EXCEPTION BAD IMAGE SIZE")
|
||||
}
|
||||
|
||||
var resultBtm = Bitmap.createBitmap(btm.width, btm.height, Bitmap.Config.ARGB_8888)
|
||||
|
||||
var offsetX = resultBtm.width + 1
|
||||
var offsetY = resultBtm.height + 1
|
||||
|
||||
var lastX = 0
|
||||
var lastY = 0
|
||||
|
||||
for (y in 0 until btm.height) {
|
||||
for (x in 0 until btm.width) {
|
||||
if (bitmapBuffer.getPixel(x, y) == btm.getPixel(x, y)) {
|
||||
resultBtm.setPixel(x, y, Color.TRANSPARENT)
|
||||
} else {
|
||||
resultBtm.setPixel(x, y, btm.getPixel(x, y))
|
||||
if (x < offsetX)
|
||||
offsetX = x
|
||||
if (y < offsetY)
|
||||
offsetY = y
|
||||
if (x > lastX)
|
||||
lastX = x
|
||||
if (y > lastY)
|
||||
lastY = y
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lastX++
|
||||
lastY++
|
||||
|
||||
val newWidth = lastX - offsetX
|
||||
val newHeight = lastY - offsetY
|
||||
|
||||
resultBtm = Bitmap.createBitmap(resultBtm, offsetX, offsetY, newWidth, newHeight)
|
||||
|
||||
return Triple(resultBtm, offsetX, offsetY)
|
||||
}
|
||||
}
|
||||
|
||||
/** Current Frame. **/
|
||||
|
@ -95,6 +141,9 @@ class ApngEncoder(
|
|||
// TODO DOC + CODE
|
||||
private var optimise : Boolean = true
|
||||
|
||||
// TODO DOC + CODE
|
||||
private var bitmapBuffer : Bitmap? = null
|
||||
|
||||
init {
|
||||
outputStream.write(Utils.pngSignature)
|
||||
writeHeader()
|
||||
|
@ -550,4 +599,6 @@ class ApngEncoder(
|
|||
i++
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -2,4 +2,5 @@ package oupson.apng.utils
|
|||
|
||||
import android.widget.ImageView
|
||||
|
||||
@Deprecated("Deprecated, Use ApngEncoder and ApngDecoder instead", level = DeprecationLevel.WARNING)
|
||||
class ApngAnimatorOptions(val scaleType: ImageView.ScaleType? = ImageView.ScaleType.FIT_CENTER)
|