Adding support for first frame not in animation

Fixing a bug
This commit is contained in:
Oupson 2020-09-23 21:09:58 +02:00
parent 39fdc31aaa
commit dfc427a54f
4 changed files with 52 additions and 20 deletions

View File

@ -15,7 +15,6 @@ import java.util.zip.DeflaterOutputStream
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
// TODO ADD SUPPORT FOR FIRST FRAME NOT IN ANIM
// TODO OPTIMISE APNG // TODO OPTIMISE APNG
/** /**
* A class to write APNG. * A class to write APNG.
@ -90,6 +89,9 @@ class ExperimentalApngEncoder(
/** Number of loop of the animation, zero to infinite **/ /** Number of loop of the animation, zero to infinite **/
private var repetitionCount: Int = 0 private var repetitionCount: Int = 0
/** If the first frame should be included in the animation **/
private var firstFrameInAnim: Boolean = true
init { init {
outputStream.write(Utils.pngSignature) outputStream.write(Utils.pngSignature)
writeHeader() writeHeader()
@ -139,9 +141,9 @@ class ExperimentalApngEncoder(
} }
/** /**
* Set the compression level * Set the compression level.
* @param compressionLevel A integer between 0 and 9 (not include) * @param compressionLevel A integer between 0 and 9 (not include).
* @return [ExperimentalApngEncoder] for chaining * @return [ExperimentalApngEncoder] for chaining.
*/ */
fun compressionLevel(compressionLevel: Int): ExperimentalApngEncoder { fun compressionLevel(compressionLevel: Int): ExperimentalApngEncoder {
if (compressionLevel in 0..9) { if (compressionLevel in 0..9) {
@ -156,6 +158,16 @@ class ExperimentalApngEncoder(
return this return this
} }
/**
* Set if the first frame should be included in the animation.
* @param firstFrameInAnim A boolean.
* @return [ExperimentalApngEncoder] for chaining.
*/
fun firstFrameInAnim(firstFrameInAnim: Boolean): ExperimentalApngEncoder {
this.firstFrameInAnim = firstFrameInAnim
return this
}
/** /**
* Write a frame into the output stream. * Write a frame into the output stream.
* @param inputStream An input stream that will be decoded in order to be written in the animation. Not freed. * @param inputStream An input stream that will be decoded in order to be written in the animation. Not freed.
@ -221,9 +233,10 @@ class ExperimentalApngEncoder(
else if (btm.height > height) else if (btm.height > height)
throw InvalidFrameSizeException("Frame height must be inferior or equal at the animation height") throw InvalidFrameSizeException("Frame height must be inferior or equal at the animation height")
writeFCTL(btm, delay, disposeOp, blendOp, xOffsets, yOffsets) if (firstFrameInAnim || currentFrame != 0)
writeFCTL(btm, delay, disposeOp, blendOp, xOffsets, yOffsets)
writeImageData(btm) writeImageData(btm)
currentSeq++ currentFrame++
} }
/** /**

View File

@ -39,6 +39,7 @@ class CreatorActivity : AppCompatActivity() {
private var items: ArrayList<Pair<Uri, Int>> = ArrayList() private var items: ArrayList<Pair<Uri, Int>> = ArrayList()
private var adapter: ImageAdapter? = null private var adapter: ImageAdapter? = null
private var firstFrameInAnim = true
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -84,6 +85,7 @@ class CreatorActivity : AppCompatActivity() {
override fun onCreateOptionsMenu(menu: Menu?): Boolean { override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.creator_menu, menu) menuInflater.inflate(R.menu.creator_menu, menu)
menu?.findItem(R.id.menu_first_frame_in_anim)?.isChecked = true
return true return true
} }
@ -128,6 +130,7 @@ class CreatorActivity : AppCompatActivity() {
maxHeight, maxHeight,
items.size items.size
).compressionLevel(9) ).compressionLevel(9)
.firstFrameInAnim(firstFrameInAnim)
items.forEachIndexed { i, uri -> items.forEachIndexed { i, uri ->
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG)
Log.v(TAG, "Encoding frame $i") Log.v(TAG, "Encoding frame $i")
@ -213,6 +216,8 @@ class CreatorActivity : AppCompatActivity() {
maxHeight, maxHeight,
items.size items.size
).compressionLevel(9) ).compressionLevel(9)
.firstFrameInAnim(firstFrameInAnim)
items.forEach { uri -> items.forEach { uri ->
println("delay : ${uri.second.toFloat()}ms") println("delay : ${uri.second.toFloat()}ms")
val str = contentResolver.openInputStream(uri.first) ?: return@forEach val str = contentResolver.openInputStream(uri.first) ?: return@forEach
@ -236,6 +241,7 @@ class CreatorActivity : AppCompatActivity() {
) )
) )
type = "image/png" type = "image/png"
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
} }
startActivity( startActivity(
Intent.createChooser( Intent.createChooser(
@ -285,6 +291,11 @@ class CreatorActivity : AppCompatActivity() {
adapter?.notifyDataSetChanged() adapter?.notifyDataSetChanged()
true true
} }
R.id.menu_first_frame_in_anim -> {
item.isChecked = !item.isChecked
firstFrameInAnim = item.isChecked
true
}
else -> if (item != null) super.onOptionsItemSelected(item) else true else -> if (item != null) super.onOptionsItemSelected(item) else true
} }
} }
@ -333,6 +344,8 @@ class CreatorActivity : AppCompatActivity() {
maxHeight, maxHeight,
items.size items.size
).compressionLevel(9) ).compressionLevel(9)
.firstFrameInAnim(firstFrameInAnim)
items.forEach { uri -> items.forEach { uri ->
// println("delay : ${adapter?.delay?.get(i)?.toFloat() ?: 1000f}ms") // println("delay : ${adapter?.delay?.get(i)?.toFloat() ?: 1000f}ms")
val str = val str =

View File

@ -1,38 +1,43 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"> xmlns:app="http://schemas.android.com/apk/res-auto">
<item <item
android:id="@+id/menu_save_apng" android:id="@+id/menu_save_apng"
android:icon="@drawable/ic_save_white_24dp" android:icon="@drawable/ic_save_white_24dp"
android:title="@string/save" android:title="@string/save"
app:showAsAction="ifRoom" app:iconTint="@color/control"
app:iconTint="@color/control"/> app:showAsAction="ifRoom" />
<item <item
android:id="@+id/menu_create_apng" android:id="@+id/menu_create_apng"
android:icon="@drawable/ic_play_arrow_white_24dp" android:icon="@drawable/ic_play_arrow_white_24dp"
android:title="@string/create" android:title="@string/create"
app:showAsAction="ifRoom" app:iconTint="@color/control"
app:iconTint="@color/control"/> app:showAsAction="ifRoom" />
<item <item
android:id="@+id/menu_share_apng" android:id="@+id/menu_share_apng"
android:icon="@drawable/ic_share_share_24dp" android:icon="@drawable/ic_share_share_24dp"
android:title="@string/share" android:title="@string/share"
app:showAsAction="ifRoom" app:iconTint="@color/control"
app:iconTint="@color/control"/> app:showAsAction="ifRoom" />
<item <item
android:id="@+id/menu_set_all_duration" android:id="@+id/menu_set_all_duration"
android:icon="@drawable/ic_access_time_white_24dp" android:icon="@drawable/ic_access_time_white_24dp"
android:title="@string/set_all_duration" android:title="@string/set_all_duration"
app:showAsAction="ifRoom" app:iconTint="@color/control"
app:iconTint="@color/control"/> app:showAsAction="ifRoom" />
<item <item
android:id="@+id/menu_clear" android:id="@+id/menu_clear"
android:title="@string/clear" android:title="@string/clear"
app:showAsAction="never" app:iconTint="@color/control"
app:iconTint="@color/control" /> app:showAsAction="never" />
<item
android:id="@+id/menu_first_frame_in_anim"
android:checkable="true"
android:title="@string/menu_first_frame_in_anim"
app:showAsAction="never|withText" />
</menu> </menu>

View File

@ -16,6 +16,7 @@
<string name="set_all_duration">Set duration of all frames</string> <string name="set_all_duration">Set duration of all frames</string>
<string name="done">Done</string> <string name="done">Done</string>
<string name="clear">Clear</string> <string name="clear">Clear</string>
<string name="menu_first_frame_in_anim">First frame in animation</string>
<string name="open">open</string> <string name="open">open</string>
<string name="close">close</string> <string name="close">close</string>