Initial coroutine support for decodeApng
This commit is contained in:
parent
7d7b02f2b9
commit
ffb60346a7
|
@ -94,15 +94,17 @@ class ApngDecoder {
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun decodeApng(
|
suspend fun decodeApng(
|
||||||
context: Context,
|
context: Context,
|
||||||
inStream: InputStream,
|
inStream: InputStream,
|
||||||
config: Config = Config()
|
config: Config = Config()
|
||||||
): Drawable {
|
): Drawable = withContext(Dispatchers.Default) {
|
||||||
val inputStream = BufferedInputStream(inStream)
|
val inputStream = BufferedInputStream(inStream)
|
||||||
val bytes = ByteArray(8)
|
val bytes = ByteArray(8)
|
||||||
inputStream.mark(8)
|
inputStream.mark(8)
|
||||||
inputStream.read(bytes)
|
withContext(Dispatchers.IO) {
|
||||||
|
inputStream.read(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
if (isPng(bytes)) {
|
if (isPng(bytes)) {
|
||||||
var png: ByteArrayOutputStream? = null
|
var png: ByteArrayOutputStream? = null
|
||||||
|
@ -131,15 +133,25 @@ class ApngDecoder {
|
||||||
var byteRead: Int
|
var byteRead: Int
|
||||||
val lengthChunk = ByteArray(4)
|
val lengthChunk = ByteArray(4)
|
||||||
do {
|
do {
|
||||||
byteRead = inputStream.read(lengthChunk)
|
val length : Int
|
||||||
|
val chunk : ByteArray
|
||||||
|
if (withContext(Dispatchers.IO) {
|
||||||
|
byteRead = inputStream.read(lengthChunk)
|
||||||
|
|
||||||
if (byteRead == -1)
|
|
||||||
|
if (byteRead != -1) {
|
||||||
|
length = Utils.uIntFromBytesBigEndian(lengthChunk)
|
||||||
|
|
||||||
|
chunk = ByteArray(length + 8)
|
||||||
|
byteRead = inputStream.read(chunk)
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
chunk = ByteArray(0)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}) {
|
||||||
break
|
break
|
||||||
|
}
|
||||||
val length = Utils.uIntFromBytesBigEndian(lengthChunk)
|
|
||||||
|
|
||||||
val chunk = ByteArray(length + 8)
|
|
||||||
byteRead = inputStream.read(chunk)
|
|
||||||
|
|
||||||
val byteArray = lengthChunk.plus(chunk)
|
val byteArray = lengthChunk.plus(chunk)
|
||||||
val chunkCRC = Utils.uIntFromBytesBigEndian(byteArray, byteArray.size - 4)
|
val chunkCRC = Utils.uIntFromBytesBigEndian(byteArray, byteArray.size - 4)
|
||||||
|
@ -411,10 +423,12 @@ class ApngDecoder {
|
||||||
crC32.update(Utils.IEND, 0, Utils.IEND.size)
|
crC32.update(Utils.IEND, 0, Utils.IEND.size)
|
||||||
it.write(Utils.IEND)
|
it.write(Utils.IEND)
|
||||||
it.write(Utils.uIntToByteArray(crC32.value.toInt()))
|
it.write(Utils.uIntToByteArray(crC32.value.toInt()))
|
||||||
inputStream.close()
|
withContext(Dispatchers.IO) {
|
||||||
|
inputStream.close()
|
||||||
|
}
|
||||||
|
|
||||||
val pngBytes = it.toByteArray()
|
val pngBytes = it.toByteArray()
|
||||||
return BitmapDrawable(
|
return@withContext BitmapDrawable(
|
||||||
context.resources,
|
context.resources,
|
||||||
BitmapFactory.decodeByteArray(
|
BitmapFactory.decodeByteArray(
|
||||||
pngBytes,
|
pngBytes,
|
||||||
|
@ -509,26 +523,35 @@ class ApngDecoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else throw BadCRCException()
|
} else throw BadCRCException()
|
||||||
} while (byteRead != -1)
|
} while (byteRead != -1 && isActive)
|
||||||
inputStream.close()
|
withContext(Dispatchers.IO) {
|
||||||
return drawable
|
inputStream.close()
|
||||||
|
}
|
||||||
|
return@withContext drawable
|
||||||
} else {
|
} else {
|
||||||
if (BuildConfig.DEBUG)
|
if (BuildConfig.DEBUG)
|
||||||
Log.i(TAG, "Decoding non APNG stream")
|
Log.i(TAG, "Decoding non APNG stream")
|
||||||
inputStream.reset()
|
inputStream.reset()
|
||||||
|
|
||||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
return@withContext if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
val bytesRead = inputStream.readBytes()
|
val bytesRead : ByteArray
|
||||||
inputStream.close()
|
withContext(Dispatchers.IO) {
|
||||||
|
bytesRead = inputStream.readBytes()
|
||||||
|
inputStream.close()
|
||||||
|
}
|
||||||
val buf = ByteBuffer.wrap(bytesRead)
|
val buf = ByteBuffer.wrap(bytesRead)
|
||||||
val source = ImageDecoder.createSource(buf)
|
val source = ImageDecoder.createSource(buf)
|
||||||
ImageDecoder.decodeDrawable(source)
|
withContext(Dispatchers.IO) {
|
||||||
|
ImageDecoder.decodeDrawable(source)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
val drawable = Drawable.createFromStream(
|
val drawable = Drawable.createFromStream(
|
||||||
inputStream,
|
inputStream,
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
inputStream.close()
|
withContext(Dispatchers.IO) {
|
||||||
|
inputStream.close()
|
||||||
|
}
|
||||||
drawable
|
drawable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -544,7 +567,7 @@ class ApngDecoder {
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
// TODO DOCUMENT
|
// TODO DOCUMENT
|
||||||
fun decodeApng(
|
suspend fun decodeApng(
|
||||||
context: Context,
|
context: Context,
|
||||||
file: File,
|
file: File,
|
||||||
config: Config = Config()
|
config: Config = Config()
|
||||||
|
@ -563,7 +586,7 @@ class ApngDecoder {
|
||||||
*/
|
*/
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun decodeApng(
|
suspend fun decodeApng(
|
||||||
context: Context,
|
context: Context,
|
||||||
uri: Uri,
|
uri: Uri,
|
||||||
config: Config = Config()
|
config: Config = Config()
|
||||||
|
@ -585,7 +608,7 @@ class ApngDecoder {
|
||||||
*/
|
*/
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun decodeApng(
|
suspend fun decodeApng(
|
||||||
context: Context,
|
context: Context,
|
||||||
@RawRes res: Int,
|
@RawRes res: Int,
|
||||||
config: Config = Config()
|
config: Config = Config()
|
||||||
|
@ -637,12 +660,14 @@ class ApngDecoder {
|
||||||
config: Config = Config(),
|
config: Config = Config(),
|
||||||
scope : CoroutineScope = GlobalScope
|
scope : CoroutineScope = GlobalScope
|
||||||
) {
|
) {
|
||||||
scope.launch(Dispatchers.IO) {
|
scope.launch(Dispatchers.Default) {
|
||||||
try {
|
try {
|
||||||
val drawable =
|
val drawable =
|
||||||
decodeApng(
|
decodeApng(
|
||||||
context,
|
context,
|
||||||
FileInputStream(file),
|
withContext(Dispatchers.IO) {
|
||||||
|
FileInputStream(file)
|
||||||
|
},
|
||||||
config
|
config
|
||||||
)
|
)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
|
@ -681,7 +706,7 @@ class ApngDecoder {
|
||||||
scope : CoroutineScope = GlobalScope
|
scope : CoroutineScope = GlobalScope
|
||||||
) {
|
) {
|
||||||
val inputStream = context.contentResolver.openInputStream(uri)!!
|
val inputStream = context.contentResolver.openInputStream(uri)!!
|
||||||
scope.launch(Dispatchers.IO) {
|
scope.launch(Dispatchers.Default) {
|
||||||
try {
|
try {
|
||||||
val drawable =
|
val drawable =
|
||||||
decodeApng(
|
decodeApng(
|
||||||
|
@ -723,7 +748,7 @@ class ApngDecoder {
|
||||||
config: Config = Config(),
|
config: Config = Config(),
|
||||||
scope : CoroutineScope = GlobalScope
|
scope : CoroutineScope = GlobalScope
|
||||||
) {
|
) {
|
||||||
scope.launch(Dispatchers.IO) {
|
scope.launch(Dispatchers.Default) {
|
||||||
try {
|
try {
|
||||||
val drawable =
|
val drawable =
|
||||||
decodeApng(
|
decodeApng(
|
||||||
|
@ -767,7 +792,7 @@ class ApngDecoder {
|
||||||
config: Config = Config(),
|
config: Config = Config(),
|
||||||
scope : CoroutineScope = GlobalScope
|
scope : CoroutineScope = GlobalScope
|
||||||
) {
|
) {
|
||||||
scope.launch(Dispatchers.IO) {
|
scope.launch(Dispatchers.Default) {
|
||||||
try {
|
try {
|
||||||
val drawable = decodeApng(
|
val drawable = decodeApng(
|
||||||
context,
|
context,
|
||||||
|
@ -813,7 +838,7 @@ class ApngDecoder {
|
||||||
config: Config = Config(),
|
config: Config = Config(),
|
||||||
scope : CoroutineScope = GlobalScope
|
scope : CoroutineScope = GlobalScope
|
||||||
) {
|
) {
|
||||||
scope.launch(Dispatchers.IO) {
|
scope.launch(Dispatchers.Default) {
|
||||||
try {
|
try {
|
||||||
if (string.startsWith("http://") || string.startsWith("https://")) {
|
if (string.startsWith("http://") || string.startsWith("https://")) {
|
||||||
decodeApngAsyncInto(
|
decodeApngAsyncInto(
|
||||||
|
|
Loading…
Reference in New Issue