New config class
This commit is contained in:
parent
d4924627cf
commit
6b90282056
|
@ -47,6 +47,12 @@ class ApngDecoder {
|
||||||
fun onError(error: Exception)
|
fun onError(error: Exception)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class Config(
|
||||||
|
val speed: Float = 1f,
|
||||||
|
val bitmapConfig: Bitmap.Config = Bitmap.Config.ARGB_8888,
|
||||||
|
val decodeCoverFrame: Boolean = true
|
||||||
|
)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "ApngDecoder"
|
private const val TAG = "ApngDecoder"
|
||||||
private val zeroLength = byteArrayOf(0x00, 0x00, 0x00, 0x00)
|
private val zeroLength = byteArrayOf(0x00, 0x00, 0x00, 0x00)
|
||||||
|
@ -68,15 +74,14 @@ class ApngDecoder {
|
||||||
* @param config Configuration applied to the bitmap added to the animation. Please note that the frame is decoded in ARGB_8888 and converted after, for the buffer.
|
* @param config Configuration applied to the bitmap added to the animation. Please note that the frame is decoded in ARGB_8888 and converted after, for the buffer.
|
||||||
* @return [AnimationDrawable] if successful and an [AnimatedImageDrawable] if the image decoded is not an APNG but a gif. If it is not an animated image, it is a [Drawable].
|
* @return [AnimationDrawable] if successful and an [AnimatedImageDrawable] if the image decoded is not an APNG but a gif. If it is not an animated image, it is a [Drawable].
|
||||||
*/
|
*/
|
||||||
// TODO BETTER CONFIG (Maybe data class with speed, config, and a settings to ignore cover frame ?)
|
// TODO DOCUMENT CONFIG
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun decodeApng(
|
fun decodeApng(
|
||||||
context: Context,
|
context: Context,
|
||||||
inStream: InputStream,
|
inStream: InputStream,
|
||||||
speed: Float = 1f,
|
config: Config = Config()
|
||||||
config: Bitmap.Config = Bitmap.Config.ARGB_8888
|
|
||||||
): Drawable {
|
): Drawable {
|
||||||
val inputStream = BufferedInputStream(inStream)
|
val inputStream = BufferedInputStream(inStream)
|
||||||
val bytes = ByteArray(8)
|
val bytes = ByteArray(8)
|
||||||
|
@ -127,6 +132,7 @@ class ApngDecoder {
|
||||||
when {
|
when {
|
||||||
name.contentEquals(Utils.fcTL) -> {
|
name.contentEquals(Utils.fcTL) -> {
|
||||||
if (png == null) {
|
if (png == null) {
|
||||||
|
if (config.decodeCoverFrame) {
|
||||||
drawable.coverFrame = cover?.let {
|
drawable.coverFrame = cover?.let {
|
||||||
it.write(zeroLength)
|
it.write(zeroLength)
|
||||||
// Generate crc for IEND
|
// Generate crc for IEND
|
||||||
|
@ -142,6 +148,8 @@ class ApngDecoder {
|
||||||
pngBytes.size
|
pngBytes.size
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
cover = null
|
||||||
} else {
|
} else {
|
||||||
// Add IEND body length : 0
|
// Add IEND body length : 0
|
||||||
png.write(zeroLength)
|
png.write(zeroLength)
|
||||||
|
@ -187,18 +195,18 @@ class ApngDecoder {
|
||||||
drawable.addFrame(
|
drawable.addFrame(
|
||||||
BitmapDrawable(
|
BitmapDrawable(
|
||||||
context.resources,
|
context.resources,
|
||||||
if (btm.config != config) {
|
if (btm.config != config.bitmapConfig) {
|
||||||
if (BuildConfig.DEBUG)
|
if (BuildConfig.DEBUG)
|
||||||
Log.v(
|
Log.v(
|
||||||
TAG,
|
TAG,
|
||||||
"Bitmap Config : ${btm.config}, Config : $config"
|
"Bitmap Config : ${btm.config}, Config : $config"
|
||||||
)
|
)
|
||||||
btm.copy(config, btm.isMutable)
|
btm.copy(config.bitmapConfig, btm.isMutable)
|
||||||
} else {
|
} else {
|
||||||
btm
|
btm
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
(delay / speed).toInt()
|
(delay / config.speed).toInt()
|
||||||
)
|
)
|
||||||
|
|
||||||
when (disposeOp) {
|
when (disposeOp) {
|
||||||
|
@ -337,18 +345,18 @@ class ApngDecoder {
|
||||||
drawable.addFrame(
|
drawable.addFrame(
|
||||||
BitmapDrawable(
|
BitmapDrawable(
|
||||||
context.resources,
|
context.resources,
|
||||||
if (btm.config != config) {
|
if (btm.config != config.bitmapConfig) {
|
||||||
if (BuildConfig.DEBUG)
|
if (BuildConfig.DEBUG)
|
||||||
Log.v(
|
Log.v(
|
||||||
TAG,
|
TAG,
|
||||||
"Bitmap Config : ${btm.config}, Config : $config"
|
"Bitmap Config : ${btm.config}, Config : $config"
|
||||||
)
|
)
|
||||||
btm.copy(config, btm.isMutable)
|
btm.copy(config.bitmapConfig, btm.isMutable)
|
||||||
} else {
|
} else {
|
||||||
btm
|
btm
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
(delay / speed).toInt()
|
(delay / config.speed).toInt()
|
||||||
)
|
)
|
||||||
|
|
||||||
when (disposeOp) {
|
when (disposeOp) {
|
||||||
|
@ -513,15 +521,15 @@ class ApngDecoder {
|
||||||
*/
|
*/
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
// TODO DOCUMENT
|
||||||
fun decodeApng(
|
fun decodeApng(
|
||||||
context: Context,
|
context: Context,
|
||||||
file: File,
|
file: File,
|
||||||
speed: Float = 1f,
|
config: Config = Config()
|
||||||
config: Bitmap.Config = Bitmap.Config.ARGB_8888
|
|
||||||
): Drawable =
|
): Drawable =
|
||||||
decodeApng(
|
decodeApng(
|
||||||
context,
|
context,
|
||||||
FileInputStream(file), speed, config
|
FileInputStream(file), config
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -537,14 +545,12 @@ class ApngDecoder {
|
||||||
fun decodeApng(
|
fun decodeApng(
|
||||||
context: Context,
|
context: Context,
|
||||||
uri: Uri,
|
uri: Uri,
|
||||||
speed: Float = 1f,
|
config: Config = Config()
|
||||||
config: Bitmap.Config = Bitmap.Config.ARGB_8888
|
|
||||||
): Drawable {
|
): Drawable {
|
||||||
val inputStream = context.contentResolver.openInputStream(uri)!!
|
val inputStream = context.contentResolver.openInputStream(uri)!!
|
||||||
return decodeApng(
|
return decodeApng(
|
||||||
context,
|
context,
|
||||||
inputStream,
|
inputStream,
|
||||||
speed,
|
|
||||||
config
|
config
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -562,13 +568,11 @@ class ApngDecoder {
|
||||||
fun decodeApng(
|
fun decodeApng(
|
||||||
context: Context,
|
context: Context,
|
||||||
@RawRes res: Int,
|
@RawRes res: Int,
|
||||||
speed: Float = 1f,
|
config: Config = Config()
|
||||||
config: Bitmap.Config = Bitmap.Config.ARGB_8888
|
|
||||||
): Drawable =
|
): Drawable =
|
||||||
decodeApng(
|
decodeApng(
|
||||||
context,
|
context,
|
||||||
context.resources.openRawResource(res),
|
context.resources.openRawResource(res),
|
||||||
speed,
|
|
||||||
config
|
config
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -585,14 +589,12 @@ class ApngDecoder {
|
||||||
suspend fun decodeApng(
|
suspend fun decodeApng(
|
||||||
context: Context,
|
context: Context,
|
||||||
url: URL,
|
url: URL,
|
||||||
speed: Float = 1f,
|
config: Config = Config()
|
||||||
config: Bitmap.Config = Bitmap.Config.ARGB_8888
|
|
||||||
) =
|
) =
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
decodeApng(
|
decodeApng(
|
||||||
context,
|
context,
|
||||||
ByteArrayInputStream(Loader.load(url)),
|
ByteArrayInputStream(Loader.load(url)),
|
||||||
speed,
|
|
||||||
config
|
config
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -613,9 +615,8 @@ class ApngDecoder {
|
||||||
context: Context,
|
context: Context,
|
||||||
file: File,
|
file: File,
|
||||||
imageView: ImageView,
|
imageView: ImageView,
|
||||||
speed: Float = 1f,
|
|
||||||
callback: Callback? = null,
|
callback: Callback? = null,
|
||||||
config: Bitmap.Config = Bitmap.Config.ARGB_8888
|
config: Config = Config()
|
||||||
) {
|
) {
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
|
@ -623,7 +624,6 @@ class ApngDecoder {
|
||||||
decodeApng(
|
decodeApng(
|
||||||
context,
|
context,
|
||||||
FileInputStream(file),
|
FileInputStream(file),
|
||||||
speed,
|
|
||||||
config
|
config
|
||||||
)
|
)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
|
@ -658,9 +658,8 @@ class ApngDecoder {
|
||||||
context: Context,
|
context: Context,
|
||||||
uri: Uri,
|
uri: Uri,
|
||||||
imageView: ImageView,
|
imageView: ImageView,
|
||||||
speed: Float = 1f,
|
|
||||||
callback: Callback? = null,
|
callback: Callback? = null,
|
||||||
config: Bitmap.Config = Bitmap.Config.ARGB_8888
|
config: Config = Config()
|
||||||
) {
|
) {
|
||||||
val inputStream = context.contentResolver.openInputStream(uri)!!
|
val inputStream = context.contentResolver.openInputStream(uri)!!
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
@ -669,7 +668,6 @@ class ApngDecoder {
|
||||||
decodeApng(
|
decodeApng(
|
||||||
context,
|
context,
|
||||||
inputStream,
|
inputStream,
|
||||||
speed,
|
|
||||||
config
|
config
|
||||||
)
|
)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
|
@ -703,9 +701,8 @@ class ApngDecoder {
|
||||||
fun decodeApngAsyncInto(
|
fun decodeApngAsyncInto(
|
||||||
context: Context, @RawRes res: Int,
|
context: Context, @RawRes res: Int,
|
||||||
imageView: ImageView,
|
imageView: ImageView,
|
||||||
speed: Float = 1f,
|
|
||||||
callback: Callback? = null,
|
callback: Callback? = null,
|
||||||
config: Bitmap.Config = Bitmap.Config.ARGB_8888
|
config: Config = Config()
|
||||||
) {
|
) {
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
|
@ -713,7 +710,6 @@ class ApngDecoder {
|
||||||
decodeApng(
|
decodeApng(
|
||||||
context,
|
context,
|
||||||
context.resources.openRawResource(res),
|
context.resources.openRawResource(res),
|
||||||
speed,
|
|
||||||
config
|
config
|
||||||
)
|
)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
|
@ -749,9 +745,8 @@ class ApngDecoder {
|
||||||
context: Context,
|
context: Context,
|
||||||
url: URL,
|
url: URL,
|
||||||
imageView: ImageView,
|
imageView: ImageView,
|
||||||
speed: Float = 1f,
|
|
||||||
callback: Callback? = null,
|
callback: Callback? = null,
|
||||||
config: Bitmap.Config = Bitmap.Config.ARGB_8888
|
config: Config = Config()
|
||||||
) {
|
) {
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
|
@ -762,7 +757,6 @@ class ApngDecoder {
|
||||||
url
|
url
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
speed,
|
|
||||||
config
|
config
|
||||||
)
|
)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
|
@ -797,9 +791,8 @@ class ApngDecoder {
|
||||||
context: Context,
|
context: Context,
|
||||||
string: String,
|
string: String,
|
||||||
imageView: ImageView,
|
imageView: ImageView,
|
||||||
speed: Float = 1f,
|
|
||||||
callback: Callback? = null,
|
callback: Callback? = null,
|
||||||
config: Bitmap.Config = Bitmap.Config.ARGB_8888
|
config: Config = Config()
|
||||||
) {
|
) {
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
|
@ -808,7 +801,6 @@ class ApngDecoder {
|
||||||
context,
|
context,
|
||||||
URL(string),
|
URL(string),
|
||||||
imageView,
|
imageView,
|
||||||
speed,
|
|
||||||
callback,
|
callback,
|
||||||
config
|
config
|
||||||
)
|
)
|
||||||
|
@ -820,7 +812,6 @@ class ApngDecoder {
|
||||||
context,
|
context,
|
||||||
Uri.parse(pathToLoad),
|
Uri.parse(pathToLoad),
|
||||||
imageView,
|
imageView,
|
||||||
speed,
|
|
||||||
callback,
|
callback,
|
||||||
config
|
config
|
||||||
)
|
)
|
||||||
|
@ -829,7 +820,7 @@ class ApngDecoder {
|
||||||
decodeApng(
|
decodeApng(
|
||||||
context,
|
context,
|
||||||
context.assets.open(string.replace("file:///android_asset/", "")),
|
context.assets.open(string.replace("file:///android_asset/", "")),
|
||||||
speed,
|
|
||||||
config
|
config
|
||||||
)
|
)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
|
@ -861,7 +852,8 @@ class ApngDecoder {
|
||||||
* @return [ByteArray] The generated IHDR.
|
* @return [ByteArray] The generated IHDR.
|
||||||
*/
|
*/
|
||||||
private fun generateIhdr(ihdrOfApng: ByteArray, width: Int, height: Int): ByteArray {
|
private fun generateIhdr(ihdrOfApng: ByteArray, width: Int, height: Int): ByteArray {
|
||||||
val ihdr = ByteArray(0xD + 4 + 4 + 4) // 0xD (IHDR body length) + 4 (0x0, 0x0, 0x0, 0xD : the chunk length) + 4 : IHDR + 4 : CRC
|
val ihdr =
|
||||||
|
ByteArray(0xD + 4 + 4 + 4) // 0xD (IHDR body length) + 4 (0x0, 0x0, 0x0, 0xD : the chunk length) + 4 : IHDR + 4 : CRC
|
||||||
|
|
||||||
// Add chunk body length
|
// Add chunk body length
|
||||||
System.arraycopy(Utils.uIntToByteArray(0xD), 0, ihdr, 0, 4)
|
System.arraycopy(Utils.uIntToByteArray(0xD), 0, ihdr, 0, 4)
|
||||||
|
|
|
@ -37,7 +37,7 @@ class ApngDecoderFragment : Fragment() {
|
||||||
this.context!!,
|
this.context!!,
|
||||||
URL("https://metagif.files.wordpress.com/2015/01/bugbuckbunny.png"),
|
URL("https://metagif.files.wordpress.com/2015/01/bugbuckbunny.png"),
|
||||||
imageView,
|
imageView,
|
||||||
config = Bitmap.Config.RGB_565,
|
config = ApngDecoder.Config(bitmapConfig = Bitmap.Config.RGB_565, decodeCoverFrame = false),
|
||||||
callback = object : ApngDecoder.Callback {
|
callback = object : ApngDecoder.Callback {
|
||||||
override fun onSuccess(drawable: Drawable) {
|
override fun onSuccess(drawable: Drawable) {
|
||||||
if (BuildConfig.DEBUG)
|
if (BuildConfig.DEBUG)
|
||||||
|
|
|
@ -39,7 +39,7 @@ public class JavaFragment extends Fragment {
|
||||||
if (imageView != null && context != null) {
|
if (imageView != null && context != null) {
|
||||||
if (BuildConfig.DEBUG)
|
if (BuildConfig.DEBUG)
|
||||||
Log.v(TAG, "Loading " + imageUrl);
|
Log.v(TAG, "Loading " + imageUrl);
|
||||||
ApngDecoder.decodeApngAsyncInto(context, imageUrl, imageView, 1f, new ApngDecoder.Callback() {
|
ApngDecoder.decodeApngAsyncInto(context, imageUrl, imageView, new ApngDecoder.Callback() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(@NotNull Drawable drawable) {
|
public void onSuccess(@NotNull Drawable drawable) {
|
||||||
if (BuildConfig.DEBUG)
|
if (BuildConfig.DEBUG)
|
||||||
|
|
Loading…
Reference in New Issue