Working on ExperimentalApngEncoder.kt

This commit is contained in:
Oupson 2020-09-20 10:06:49 +02:00
parent be3322a34e
commit d8d58259e1
2 changed files with 91 additions and 21 deletions

View File

@ -23,10 +23,7 @@ class ExperimentalApngEncoder(
private val outputStream: OutputStream,
private val width: Int,
private val height: Int,
numberOfFrames: Int,
private val encodeAlpha: Boolean = true,
filter: Int = 0,
compressionLevel: Int = 0
numberOfFrames: Int
) {
companion object {
private const val TAG = "ExperimentalApngEncoder"
@ -66,7 +63,10 @@ class ExperimentalApngEncoder(
private var compressionLevel: Int = 0
/** The filter type. */
private var filter: Int = 0
private var filter: Int = FILTER_NONE
/** If the alpha channel must be encoded */
private var encodeAlpha : Boolean = true
/** The prior row. */
private var priorRow: ByteArray? = null
@ -74,21 +74,72 @@ class ExperimentalApngEncoder(
/** The left bytes. */
private var leftBytes: ByteArray? = null
/** Number of loop of the animation, zero to infinite **/
private var repetitionCount : Int = 0
init {
this.filter = FILTER_NONE
if (filter <= FILTER_LAST) {
this.filter = filter
}
if (compressionLevel in 0..9) {
this.compressionLevel = compressionLevel
}
outputStream.write(Utils.pngSignature)
writeHeader()
writeACTL(numberOfFrames)
}
/**
* Set if the alpha channel must be encoded.
* @param encodeAlpha If the alpha channel must be encoded.
* @return [ExperimentalApngEncoder] for chaining.
*/
@Suppress("unused")
fun encodeAlpha(encodeAlpha : Boolean) : ExperimentalApngEncoder {
this.encodeAlpha = encodeAlpha
return this
}
/**
* Set the filter.
* @param filter The filter.
* Values :
* - [FILTER_NONE]
* - [FILTER_SUB]
* - [FILTER_UP]
* - [FILTER_LAST]
* @return [ExperimentalApngEncoder] for chaining.
*/
@Suppress("unused")
fun filter(filter : Int) : ExperimentalApngEncoder {
if (filter <= FILTER_LAST) {
this.filter = filter
} else {
Log.e(TAG, "Invalid filter")
}
return this
}
/**
* Set the repetition count.
* @param repetitionCount The number of repetition, zero for infinite.
* @return [ExperimentalApngEncoder] for chaining.
*/
@Suppress("unused")
fun repetitionCount(repetitionCount : Int) : ExperimentalApngEncoder{
this.repetitionCount = repetitionCount
return this
}
/**
* Set the compression level
* @param compressionLevel A integer between 0 and 9 (not include)
* @return [ExperimentalApngEncoder] for chaining
*/
fun compressionLevel(compressionLevel : Int) : ExperimentalApngEncoder {
if (compressionLevel in 0..9) {
this.compressionLevel = compressionLevel
} else {
Log.e(TAG, "Invalid compression level : $compressionLevel, expected a number in range 0..9")
}
return this
}
@JvmOverloads
fun writeFrame(
inputStream: InputStream,
@ -120,7 +171,11 @@ class ExperimentalApngEncoder(
throw Exception("Height of first frame must be equal to height of APNG. (${btm.height} != $height)")
}
// TODO CHECK IF btm IS BIGGER THANT THE APNG
// TODO PROPER EXCEPTION
if (btm.width > width)
throw Exception("Frame width must be inferior or equal at the animation width")
else if (btm.height > height)
throw Exception("Frame height must be inferior or equal at the animation height")
writeFCTL(btm, delay, disposeOp, blendOp, xOffsets, yOffsets)
writeImageData(btm)
@ -193,7 +248,7 @@ class ExperimentalApngEncoder(
actl.addAll(Utils.to4Bytes(num).asList())
// Number of repeat, 0 to infinite
actl.addAll(Utils.to4Bytes(0).asList())
actl.addAll(Utils.to4Bytes(repetitionCount).asList())
outputStream.write(actl.toByteArray())
// generate crc

View File

@ -122,7 +122,12 @@ class CreatorActivity : AppCompatActivity() {
if (BuildConfig.DEBUG)
Log.i(TAG, "MaxWidth : $maxWidth; MaxHeight : $maxHeight")
val encoder = ExperimentalApngEncoder(out, maxWidth, maxHeight, items.size, compressionLevel = 9)
val encoder = ExperimentalApngEncoder(
out,
maxWidth,
maxHeight,
items.size
).compressionLevel(9)
items.forEachIndexed { i, uri ->
if (BuildConfig.DEBUG)
Log.v(TAG, "Encoding frame $i")
@ -164,7 +169,7 @@ class CreatorActivity : AppCompatActivity() {
out.close()
if (BuildConfig.DEBUG)
Log.v(TAG, "${f.length() / 1000}ko")
Log.v(TAG, "Animation size is ${f.length() / 1000}ko")
withContext(Dispatchers.Main) {
val intent = Intent(Intent.ACTION_VIEW)
@ -202,7 +207,12 @@ class CreatorActivity : AppCompatActivity() {
str?.close()
}
val encoder = ExperimentalApngEncoder(out, maxWidth, maxHeight, items.size, compressionLevel = 9)
val encoder = ExperimentalApngEncoder(
out,
maxWidth,
maxHeight,
items.size
).compressionLevel(9)
items.forEach { uri ->
println("delay : ${uri.second.toFloat()}ms")
val str = contentResolver.openInputStream(uri.first) ?: return@forEach
@ -317,7 +327,12 @@ class CreatorActivity : AppCompatActivity() {
if (BuildConfig.DEBUG)
Log.i(TAG, "MaxWidth : $maxWidth; MaxHeight : $maxHeight")
val encoder = ExperimentalApngEncoder(out, maxWidth, maxHeight, items.size, compressionLevel = 9)
val encoder = ExperimentalApngEncoder(
out,
maxWidth,
maxHeight,
items.size
).compressionLevel(9)
items.forEach { uri ->
// println("delay : ${adapter?.delay?.get(i)?.toFloat() ?: 1000f}ms")
val str =