Work on ApngDecoder
This commit is contained in:
parent
af21d501f6
commit
4ef644632a
File diff suppressed because it is too large
Load Diff
|
@ -10,8 +10,6 @@ import android.widget.ImageView
|
||||||
import androidx.annotation.RawRes
|
import androidx.annotation.RawRes
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import oupson.apng.drawable.ApngDrawable
|
import oupson.apng.drawable.ApngDrawable
|
||||||
import oupson.apng.utils.Loader
|
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
|
@ -29,7 +27,7 @@ class ApngLoader(parent: Job? = null) {
|
||||||
* Function called when something gone wrong.
|
* Function called when something gone wrong.
|
||||||
* @param error The problem.
|
* @param error The problem.
|
||||||
*/
|
*/
|
||||||
fun onError(error: Exception)
|
fun onError(error: Throwable)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val job = SupervisorJob(parent)
|
private val job = SupervisorJob(parent)
|
||||||
|
@ -52,23 +50,26 @@ class ApngLoader(parent: Job? = null) {
|
||||||
file: File,
|
file: File,
|
||||||
imageView: ImageView,
|
imageView: ImageView,
|
||||||
config: ApngDecoder.Config = ApngDecoder.Config()
|
config: ApngDecoder.Config = ApngDecoder.Config()
|
||||||
): Drawable {
|
): Result<Drawable> {
|
||||||
val drawable =
|
val result =
|
||||||
ApngDecoder.decodeApng(
|
ApngDecoder(
|
||||||
context,
|
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
FileInputStream(file)
|
FileInputStream(file)
|
||||||
},
|
},
|
||||||
config
|
config
|
||||||
)
|
).getDecoded(context)
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
imageView.setImageDrawable(drawable)
|
if (result.isSuccess) {
|
||||||
(drawable as? AnimationDrawable)?.start()
|
withContext(Dispatchers.Main) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
val drawable = result.getOrNull()
|
||||||
(drawable as? AnimatedImageDrawable)?.start()
|
imageView.setImageDrawable(drawable)
|
||||||
|
(drawable as? AnimationDrawable)?.start()
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
|
(drawable as? AnimatedImageDrawable)?.start()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return drawable
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -83,25 +84,27 @@ class ApngLoader(parent: Job? = null) {
|
||||||
uri: Uri,
|
uri: Uri,
|
||||||
imageView: ImageView,
|
imageView: ImageView,
|
||||||
config: ApngDecoder.Config = ApngDecoder.Config()
|
config: ApngDecoder.Config = ApngDecoder.Config()
|
||||||
): Drawable {
|
): Result<Drawable> {
|
||||||
val inputStream =
|
val inputStream =
|
||||||
withContext(Dispatchers.IO) { context.contentResolver.openInputStream(uri) }
|
withContext(Dispatchers.IO) { context.contentResolver.openInputStream(uri) }
|
||||||
?: throw FileNotFoundException("Failed to load $uri") // TODO Better err ?
|
?: throw FileNotFoundException("Failed to load $uri") // TODO Result
|
||||||
val drawable =
|
val result =
|
||||||
ApngDecoder.decodeApng(
|
ApngDecoder(
|
||||||
context,
|
|
||||||
inputStream,
|
inputStream,
|
||||||
config
|
config
|
||||||
)
|
).getDecoded(context)
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
imageView.setImageDrawable(drawable)
|
if (result.isSuccess) {
|
||||||
(drawable as? AnimationDrawable)?.start()
|
withContext(Dispatchers.Main) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
val drawable = result.getOrNull()
|
||||||
(drawable as? AnimatedImageDrawable)?.start()
|
imageView.setImageDrawable(drawable)
|
||||||
|
(drawable as? AnimationDrawable)?.start()
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
|
(drawable as? AnimatedImageDrawable)?.start()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return result
|
||||||
return drawable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -115,21 +118,26 @@ class ApngLoader(parent: Job? = null) {
|
||||||
context: Context, @RawRes res: Int,
|
context: Context, @RawRes res: Int,
|
||||||
imageView: ImageView,
|
imageView: ImageView,
|
||||||
config: ApngDecoder.Config = ApngDecoder.Config()
|
config: ApngDecoder.Config = ApngDecoder.Config()
|
||||||
): Drawable {
|
): Result<Drawable> {
|
||||||
val drawable =
|
val result =
|
||||||
ApngDecoder.decodeApng(
|
ApngDecoder(
|
||||||
context,
|
withContext(Dispatchers.IO) {
|
||||||
context.resources.openRawResource(res),
|
context.resources.openRawResource(res)
|
||||||
|
},
|
||||||
config
|
config
|
||||||
)
|
).getDecoded(context)
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
imageView.setImageDrawable(drawable)
|
if (result.isSuccess) {
|
||||||
(drawable as? AnimationDrawable)?.start()
|
withContext(Dispatchers.Main) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
val drawable = result.getOrNull()
|
||||||
(drawable as? AnimatedImageDrawable)?.start()
|
imageView.setImageDrawable(drawable)
|
||||||
|
(drawable as? AnimationDrawable)?.start()
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
|
(drawable as? AnimatedImageDrawable)?.start()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return drawable
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -144,26 +152,20 @@ class ApngLoader(parent: Job? = null) {
|
||||||
url: URL,
|
url: URL,
|
||||||
imageView: ImageView,
|
imageView: ImageView,
|
||||||
config: ApngDecoder.Config = ApngDecoder.Config()
|
config: ApngDecoder.Config = ApngDecoder.Config()
|
||||||
): Drawable {
|
): Result<Drawable> {
|
||||||
|
val result = ApngDecoder.constructFromUrl(url, config).getDecoded(context)
|
||||||
val drawable = ApngDecoder.decodeApng(
|
if (result.isSuccess) {
|
||||||
context,
|
withContext(Dispatchers.Main) {
|
||||||
ByteArrayInputStream(
|
val drawable = result.getOrNull()
|
||||||
Loader.load(
|
imageView.setImageDrawable(drawable)
|
||||||
url
|
(drawable as? AnimationDrawable)?.start()
|
||||||
)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
),
|
(drawable as? AnimatedImageDrawable)?.start()
|
||||||
config
|
}
|
||||||
)
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
imageView.setImageDrawable(drawable)
|
|
||||||
(drawable as? AnimationDrawable)?.start()
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
||||||
(drawable as? AnimatedImageDrawable)?.start()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return drawable
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -179,7 +181,7 @@ class ApngLoader(parent: Job? = null) {
|
||||||
string: String,
|
string: String,
|
||||||
imageView: ImageView,
|
imageView: ImageView,
|
||||||
config: ApngDecoder.Config = ApngDecoder.Config()
|
config: ApngDecoder.Config = ApngDecoder.Config()
|
||||||
): Drawable {
|
): Result<Drawable> {
|
||||||
return if (string.startsWith("http://") || string.startsWith("https://")) {
|
return if (string.startsWith("http://") || string.startsWith("https://")) {
|
||||||
decodeApngInto(
|
decodeApngInto(
|
||||||
context,
|
context,
|
||||||
|
@ -198,21 +200,25 @@ class ApngLoader(parent: Job? = null) {
|
||||||
config
|
config
|
||||||
)
|
)
|
||||||
} else if (string.startsWith("file://android_asset/")) {
|
} else if (string.startsWith("file://android_asset/")) {
|
||||||
val drawable =
|
val inputStream = kotlin.runCatching {
|
||||||
ApngDecoder.decodeApng(
|
withContext(Dispatchers.IO) {
|
||||||
context,
|
context.assets.open(string.replace("file:///android_asset/", ""))
|
||||||
context.assets.open(string.replace("file:///android_asset/", "")),
|
}
|
||||||
|
}.onFailure {
|
||||||
config
|
return Result.failure(it)
|
||||||
)
|
}
|
||||||
withContext(Dispatchers.Main) {
|
val result = ApngDecoder(inputStream.getOrThrow(), config).getDecoded(context)
|
||||||
imageView.setImageDrawable(drawable)
|
if (result.isSuccess) {
|
||||||
(drawable as? AnimationDrawable)?.start()
|
withContext(Dispatchers.Main) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
val drawable = result.getOrNull()
|
||||||
(drawable as? AnimatedImageDrawable)?.start()
|
imageView.setImageDrawable(drawable)
|
||||||
|
(drawable as? AnimationDrawable)?.start()
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
|
(drawable as? AnimatedImageDrawable)?.start()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drawable
|
result
|
||||||
} else {
|
} else {
|
||||||
throw Exception("Cannot open string")
|
throw Exception("Cannot open string")
|
||||||
}
|
}
|
||||||
|
@ -228,7 +234,7 @@ class ApngLoader(parent: Job? = null) {
|
||||||
* @param callback [ApngLoader.Callback] to handle success and error.
|
* @param callback [ApngLoader.Callback] to handle success and error.
|
||||||
* @param config Decoder configuration
|
* @param config Decoder configuration
|
||||||
*/
|
*/
|
||||||
@Suppress("unused", "BlockingMethodInNonBlockingContext")
|
@Suppress("unused")
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun decodeApngAsyncInto(
|
fun decodeApngAsyncInto(
|
||||||
context: Context,
|
context: Context,
|
||||||
|
@ -238,11 +244,13 @@ class ApngLoader(parent: Job? = null) {
|
||||||
config: ApngDecoder.Config = ApngDecoder.Config()
|
config: ApngDecoder.Config = ApngDecoder.Config()
|
||||||
) =
|
) =
|
||||||
coroutineScope.launch(Dispatchers.Default) {
|
coroutineScope.launch(Dispatchers.Default) {
|
||||||
try {
|
val drawable = decodeApngInto(context, file, imageView, config)
|
||||||
val drawable = decodeApngInto(context, file, imageView, config)
|
withContext(Dispatchers.Main) {
|
||||||
callback?.onSuccess(drawable)
|
if (drawable.isSuccess) {
|
||||||
} catch (e: Exception) {
|
callback?.onSuccess(drawable.getOrNull()!!)
|
||||||
callback?.onError(e)
|
} else {
|
||||||
|
callback?.onError(drawable.exceptionOrNull()!!)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,11 +272,13 @@ class ApngLoader(parent: Job? = null) {
|
||||||
callback: Callback? = null,
|
callback: Callback? = null,
|
||||||
config: ApngDecoder.Config = ApngDecoder.Config()
|
config: ApngDecoder.Config = ApngDecoder.Config()
|
||||||
) = coroutineScope.launch(Dispatchers.Default) {
|
) = coroutineScope.launch(Dispatchers.Default) {
|
||||||
try {
|
val drawable = decodeApngInto(context, uri, imageView, config)
|
||||||
val drawable = decodeApngInto(context, uri, imageView, config)
|
withContext(Dispatchers.Main) {
|
||||||
callback?.onSuccess(drawable)
|
if (drawable.isSuccess) {
|
||||||
} catch (e: Exception) {
|
callback?.onSuccess(drawable.getOrNull()!!)
|
||||||
callback?.onError(e)
|
} else {
|
||||||
|
callback?.onError(drawable.exceptionOrNull()!!)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,11 +298,13 @@ class ApngLoader(parent: Job? = null) {
|
||||||
callback: Callback? = null,
|
callback: Callback? = null,
|
||||||
config: ApngDecoder.Config = ApngDecoder.Config()
|
config: ApngDecoder.Config = ApngDecoder.Config()
|
||||||
) = coroutineScope.launch(Dispatchers.Default) {
|
) = coroutineScope.launch(Dispatchers.Default) {
|
||||||
try {
|
val drawable = decodeApngInto(context, res, imageView, config)
|
||||||
val drawable = decodeApngInto(context, res, imageView, config)
|
withContext(Dispatchers.Main) {
|
||||||
callback?.onSuccess(drawable)
|
if (drawable.isSuccess) {
|
||||||
} catch (e: Exception) {
|
callback?.onSuccess(drawable.getOrNull()!!)
|
||||||
callback?.onError(e)
|
} else {
|
||||||
|
callback?.onError(drawable.exceptionOrNull()!!)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,7 +316,7 @@ class ApngLoader(parent: Job? = null) {
|
||||||
* @param callback [ApngLoader.Callback] to handle success and error.
|
* @param callback [ApngLoader.Callback] to handle success and error.
|
||||||
* @param config Decoder configuration
|
* @param config Decoder configuration
|
||||||
*/
|
*/
|
||||||
@Suppress("unused", "BlockingMethodInNonBlockingContext")
|
@Suppress("unused")
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun decodeApngAsyncInto(
|
fun decodeApngAsyncInto(
|
||||||
context: Context,
|
context: Context,
|
||||||
|
@ -313,11 +325,13 @@ class ApngLoader(parent: Job? = null) {
|
||||||
callback: Callback? = null,
|
callback: Callback? = null,
|
||||||
config: ApngDecoder.Config = ApngDecoder.Config()
|
config: ApngDecoder.Config = ApngDecoder.Config()
|
||||||
) = coroutineScope.launch(Dispatchers.Default) {
|
) = coroutineScope.launch(Dispatchers.Default) {
|
||||||
try {
|
val drawable = decodeApngInto(context, url, imageView, config)
|
||||||
val drawable = decodeApngInto(context, url, imageView, config)
|
withContext(Dispatchers.Main) {
|
||||||
callback?.onSuccess(drawable)
|
if (drawable.isSuccess) {
|
||||||
} catch (e: Exception) {
|
callback?.onSuccess(drawable.getOrNull()!!)
|
||||||
callback?.onError(e)
|
} else {
|
||||||
|
callback?.onError(drawable.exceptionOrNull()!!)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,12 +353,12 @@ class ApngLoader(parent: Job? = null) {
|
||||||
config: ApngDecoder.Config = ApngDecoder.Config()
|
config: ApngDecoder.Config = ApngDecoder.Config()
|
||||||
) =
|
) =
|
||||||
coroutineScope.launch(Dispatchers.Default) {
|
coroutineScope.launch(Dispatchers.Default) {
|
||||||
try {
|
val drawable = decodeApngInto(context, string, imageView, config)
|
||||||
val drawable = decodeApngInto(context, string, imageView, config)
|
withContext(Dispatchers.Main) {
|
||||||
callback?.onSuccess(drawable)
|
if (drawable.isSuccess) {
|
||||||
} catch (e: Exception) {
|
callback?.onSuccess(drawable.getOrNull()!!)
|
||||||
withContext(Dispatchers.Main) {
|
} else {
|
||||||
callback?.onError(e)
|
callback?.onError(drawable.exceptionOrNull()!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ class ViewerActivity : AppCompatActivity() {
|
||||||
viewerImageView,
|
viewerImageView,
|
||||||
callback = object : ApngLoader.Callback {
|
callback = object : ApngLoader.Callback {
|
||||||
override fun onSuccess(drawable: Drawable) {}
|
override fun onSuccess(drawable: Drawable) {}
|
||||||
override fun onError(error: Exception) {
|
override fun onError(error: Throwable) {
|
||||||
Log.e("ViewerActivity", "Error when loading file", error)
|
Log.e("ViewerActivity", "Error when loading file", error)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -56,7 +56,7 @@ class ApngDecoderFragment : Fragment() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onError(error: Exception) {
|
override fun onError(error: Throwable) {
|
||||||
Log.e(TAG, "onError : $error")
|
Log.e(TAG, "onError : $error")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -52,7 +52,7 @@ public class JavaFragment extends Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(@NotNull Exception error) {
|
public void onError(@NotNull Throwable error) {
|
||||||
Log.e(TAG, "Error : " + error.toString());
|
Log.e(TAG, "Error : " + error.toString());
|
||||||
}
|
}
|
||||||
}, new ApngDecoder.Config().setIsDecodingCoverFrame(false));
|
}, new ApngDecoder.Config().setIsDecodingCoverFrame(false));
|
||||||
|
|
Loading…
Reference in New Issue