Working on optimiser functionality to reduce APNG size.
Add KDOC
This commit is contained in:
parent
ed00672b0f
commit
0150810541
|
@ -30,9 +30,6 @@ class Apng {
|
|||
* If it's null the library generate a cover with the first frame
|
||||
*/
|
||||
var cover : Bitmap? = null
|
||||
set(value) {
|
||||
field = value!!
|
||||
}
|
||||
|
||||
var frames : ArrayList<Frame> = ArrayList()
|
||||
|
||||
|
@ -412,6 +409,10 @@ class Apng {
|
|||
return Bitmap.createScaledBitmap(bitmap, maxWidth, maxHeight, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the IHDR chunks.
|
||||
* @return The byteArray generated
|
||||
*/
|
||||
private fun generateIhdr(): ByteArray {
|
||||
val ihdr = ArrayList<Byte>()
|
||||
|
||||
|
@ -447,7 +448,10 @@ class Apng {
|
|||
return ihdr.toByteArray()
|
||||
}
|
||||
|
||||
// Animation Control chunk
|
||||
/**
|
||||
* Generate the animation control chunk
|
||||
* @return The byteArray generated
|
||||
*/
|
||||
private fun generateACTL(): ArrayList<Byte> {
|
||||
val res = ArrayList<Byte>()
|
||||
val actl = ArrayList<Byte>()
|
||||
|
@ -472,16 +476,38 @@ class Apng {
|
|||
return res
|
||||
}
|
||||
|
||||
fun optimise(quality : Int, maxColor : Int) {
|
||||
val apng = Apng()
|
||||
val pnn = PnnQuantizer(cover)
|
||||
cover = pnn.convert(maxColor, false)
|
||||
|
||||
/**
|
||||
* Reduce the apng size
|
||||
* @param maxColor Max color you want in the image
|
||||
* @param keepCover Keep the cover
|
||||
* @param sizePercent Reduce image width/height by percents.
|
||||
*/
|
||||
fun reduceSize( maxColor : Int, keepCover : Boolean? = null, sizePercent : Int? = null) {
|
||||
val apng = Apng()
|
||||
if (keepCover != false) {
|
||||
if (cover != null) {
|
||||
if (sizePercent != null) {
|
||||
cover = Bitmap.createScaledBitmap(cover, (cover!!.width.toFloat() * sizePercent.toFloat() / 100f).toInt(), (cover!!.height.toFloat() * sizePercent.toFloat() / 100f).toInt(), false)
|
||||
val pnn = PnnQuantizer(cover)
|
||||
cover = pnn.convert(maxColor, false)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cover = null
|
||||
}
|
||||
frames.forEach {
|
||||
val btm = BitmapFactory.decodeByteArray(it.byteArray, 0 , it.byteArray.size)
|
||||
var btm = BitmapFactory.decodeByteArray(it.byteArray, 0, it.byteArray.size)
|
||||
if (sizePercent != null) {
|
||||
btm = Bitmap.createScaledBitmap(btm, (btm!!.width.toFloat() * sizePercent.toFloat() / 100f).toInt(), (btm.height.toFloat() * sizePercent.toFloat() / 100f).toInt(), false)
|
||||
}
|
||||
val pnn = PnnQuantizer(btm)
|
||||
val btmOptimised = pnn.convert(maxColor, false)
|
||||
apng.addFrames(btmOptimised, it.delay, it.x_offsets ?: 0, it.y_offsets ?: 0, it.dispose_op, it.blend_op)
|
||||
if (sizePercent != null) {
|
||||
apng.addFrames(btmOptimised, it.delay, ((it.x_offsets ?: 0).toFloat() * sizePercent.toFloat() / 100f).toInt(), ((it.y_offsets ?: 0).toFloat() * sizePercent.toFloat() / 100f).toInt(), it.dispose_op, it.blend_op)
|
||||
} else {
|
||||
apng.addFrames(btmOptimised, it.delay, it.x_offsets ?: 0, it.y_offsets ?: 0, it.dispose_op, it.blend_op)
|
||||
}
|
||||
}
|
||||
frames = apng.frames
|
||||
}
|
||||
|
|
|
@ -6,18 +6,25 @@ import java.io.ByteArrayOutputStream
|
|||
|
||||
class Utils {
|
||||
companion object {
|
||||
|
||||
// Return true if png
|
||||
/**
|
||||
* @return True if is a png
|
||||
*/
|
||||
fun isPng(byteArray: ByteArray): Boolean {
|
||||
return byteArray.copyOfRange(0, 8).contentToString() == pngSignature.contentToString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Know if file is an APNG
|
||||
* @return True if is an APNG
|
||||
*/
|
||||
fun isApng(byteArray: ByteArray): Boolean {
|
||||
// if byteArray contain acTL
|
||||
return byteArray.toList().containsAll(byteArrayOf(0x66, 0x63, 0x54, 0x4c).toList())
|
||||
}
|
||||
|
||||
// Signature for png
|
||||
/**
|
||||
* Signature for png / APNG files
|
||||
*/
|
||||
val pngSignature: ByteArray = byteArrayOf(0x89.toByte(), 0x50.toByte(), 0x4E.toByte(), 0x47.toByte(), 0x0D.toByte(), 0x0A.toByte(), 0x1A.toByte(), 0x0A.toByte())
|
||||
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import kotlinx.android.synthetic.main.activity_main.*
|
|||
import oupson.apng.ApngAnimator
|
||||
import android.widget.Toast
|
||||
import org.jetbrains.anko.doAsync
|
||||
import org.jetbrains.anko.toast
|
||||
import oupson.apng.APNGDisassembler
|
||||
import oupson.apng.Apng
|
||||
import oupson.apng.Loader
|
||||
|
@ -23,6 +24,7 @@ class MainActivity : AppCompatActivity() {
|
|||
lateinit var animator: ApngAnimator
|
||||
|
||||
val imageUrl = "https://metagif.files.wordpress.com/2015/01/bugbuckbunny.png"
|
||||
// val imageUrl = "http://orig06.deviantart.net/7812/f/2012/233/7/5/twilight_rapidash_shaded_and_animated_by_tamalesyatole-d5bz7hd.png"
|
||||
//val imageUrl = "https://raw.githubusercontent.com/tinify/iMessage-Panda-sticker/master/StickerPackExtension/Stickers.xcstickers/Sticker%20Pack.stickerpack/panda.sticker/panda.png"
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
@ -40,8 +42,11 @@ class MainActivity : AppCompatActivity() {
|
|||
doAsync {
|
||||
Loader().load(applicationContext, URL(imageUrl)).apply {
|
||||
val a = APNGDisassembler(this).apng
|
||||
a.optimise(100, 75)
|
||||
a.reduceSize(100, false, 75)
|
||||
File(File(Environment.getExternalStorageDirectory(), "Documents"), "apng.png").writeBytes(a.toByteArray())
|
||||
runOnUiThread {
|
||||
toast("Converted ! ")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue