Parse IHDR and fcTL inside of ApngDecoder.kt instead of using dedicated class
Deprecation of Chunk.kt, fcTL.kt and IHDR.kt
This commit is contained in:
parent
b4bd0dd17e
commit
5d44b35882
|
@ -3,6 +3,7 @@ package oupson.apng.chunks
|
||||||
/**
|
/**
|
||||||
* An interface for the png chunks
|
* An interface for the png chunks
|
||||||
*/
|
*/
|
||||||
|
@Deprecated("Deprecated", level = DeprecationLevel.WARNING)
|
||||||
interface Chunk {
|
interface Chunk {
|
||||||
var body : ByteArray
|
var body : ByteArray
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package oupson.apng.chunks
|
||||||
import oupson.apng.utils.Utils
|
import oupson.apng.utils.Utils
|
||||||
|
|
||||||
// TODO REMOVE
|
// TODO REMOVE
|
||||||
|
@Deprecated("Deprecated", level = DeprecationLevel.WARNING)
|
||||||
class IHDR : Chunk {
|
class IHDR : Chunk {
|
||||||
override var body = byteArrayOf()
|
override var body = byteArrayOf()
|
||||||
var pngWidth = -1
|
var pngWidth = -1
|
||||||
|
|
|
@ -5,7 +5,7 @@ import oupson.apng.utils.Utils.Companion.decodeBlendOp
|
||||||
import oupson.apng.utils.Utils.Companion.decodeDisposeOp
|
import oupson.apng.utils.Utils.Companion.decodeDisposeOp
|
||||||
|
|
||||||
@Suppress("ClassName")
|
@Suppress("ClassName")
|
||||||
// TODO REMOVE
|
@Deprecated("Deprecated, Use ApngEncoder and ApngDecoder instead", level = DeprecationLevel.WARNING)
|
||||||
class fcTL : Chunk {
|
class fcTL : Chunk {
|
||||||
override var body : ByteArray = byteArrayOf()
|
override var body : ByteArray = byteArrayOf()
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,6 @@ import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import oupson.apng.BuildConfig
|
import oupson.apng.BuildConfig
|
||||||
import oupson.apng.Loader
|
import oupson.apng.Loader
|
||||||
import oupson.apng.chunks.IHDR
|
|
||||||
import oupson.apng.chunks.fcTL
|
|
||||||
import oupson.apng.decoder.ApngDecoder.Companion.decodeApng
|
import oupson.apng.decoder.ApngDecoder.Companion.decodeApng
|
||||||
import oupson.apng.exceptions.BadApngException
|
import oupson.apng.exceptions.BadApngException
|
||||||
import oupson.apng.exceptions.BadCRCException
|
import oupson.apng.exceptions.BadCRCException
|
||||||
|
@ -95,8 +93,9 @@ class ApngDecoder {
|
||||||
var blendOp: Utils.Companion.BlendOp = Utils.Companion.BlendOp.APNG_BLEND_OP_SOURCE
|
var blendOp: Utils.Companion.BlendOp = Utils.Companion.BlendOp.APNG_BLEND_OP_SOURCE
|
||||||
var disposeOp: Utils.Companion.DisposeOp =
|
var disposeOp: Utils.Companion.DisposeOp =
|
||||||
Utils.Companion.DisposeOp.APNG_DISPOSE_OP_NONE
|
Utils.Companion.DisposeOp.APNG_DISPOSE_OP_NONE
|
||||||
// TODO REMOVE
|
|
||||||
val ihdr = IHDR()
|
var ihdrOfApng = ByteArray(0)
|
||||||
|
|
||||||
var isApng = false
|
var isApng = false
|
||||||
|
|
||||||
val drawable = AnimationDrawable().apply {
|
val drawable = AnimationDrawable().apply {
|
||||||
|
@ -142,17 +141,33 @@ class ApngDecoder {
|
||||||
)*/ // TODO
|
)*/ // TODO
|
||||||
}
|
}
|
||||||
png = ArrayList()
|
png = ArrayList()
|
||||||
val fcTL = fcTL()
|
|
||||||
|
|
||||||
// TODO REMOVE FCTL CLASS
|
// PARSE FCTL
|
||||||
fcTL.parse(byteArray)
|
// Get the width of the png
|
||||||
delay = fcTL.delay
|
val width = Utils.uIntFromBytesBigEndian(byteArray.copyOfRange(i + 8, i + 12).map(Byte::toInt))
|
||||||
yOffset = fcTL.yOffset
|
// Get the height of the png
|
||||||
xOffset = fcTL.xOffset
|
val height = Utils.uIntFromBytesBigEndian(byteArray.copyOfRange(i + 12, i + 16).map(Byte::toInt))
|
||||||
blendOp = fcTL.blendOp
|
/*
|
||||||
disposeOp = fcTL.disposeOp
|
* The `delay_num` and `delay_den` parameters together specify a fraction indicating the time to display the current frame, in seconds.
|
||||||
val width = fcTL.pngWidth
|
* If the the value of the numerator is 0 the decoder should render the next frame as quickly as possible, though viewers may impose a reasonable lower bound.
|
||||||
val height = fcTL.pngHeight
|
*/
|
||||||
|
// Get delay numerator
|
||||||
|
val delayNum = Utils.uShortFromBytesBigEndian(byteArray.copyOfRange(i + 24, i + 26).map(Byte::toInt)).toFloat()
|
||||||
|
// Get delay denominator
|
||||||
|
var delayDen = Utils.uShortFromBytesBigEndian(byteArray.copyOfRange(i + 26, i + 28).map(Byte::toInt)).toFloat()
|
||||||
|
|
||||||
|
// If the denominator is 0, it is to be treated as if it were 100 (that is, `delay_num` then specifies 1/100ths of a second).
|
||||||
|
if (delayDen == 0f) {
|
||||||
|
delayDen = 100f
|
||||||
|
}
|
||||||
|
|
||||||
|
delay = (delayNum / delayDen * 1000)
|
||||||
|
|
||||||
|
// Get x and y offsets
|
||||||
|
xOffset = Utils.uIntFromBytesBigEndian(byteArray.copyOfRange(i + 16, i + 20).map(Byte::toInt))
|
||||||
|
yOffset = Utils.uIntFromBytesBigEndian(byteArray.copyOfRange(i + 20, i + 24).map(Byte::toInt))
|
||||||
|
blendOp = Utils.decodeBlendOp(byteArray[33].toInt())
|
||||||
|
disposeOp = Utils.decodeDisposeOp(byteArray[32].toInt())
|
||||||
|
|
||||||
if (xOffset + width > maxWidth) {
|
if (xOffset + width > maxWidth) {
|
||||||
throw BadApngException("`xOffset` + `width` must be <= `IHDR` width")
|
throw BadApngException("`xOffset` + `width` must be <= `IHDR` width")
|
||||||
|
@ -163,7 +178,7 @@ class ApngDecoder {
|
||||||
png.addAll(Utils.pngSignature.asList())
|
png.addAll(Utils.pngSignature.asList())
|
||||||
png.addAll(
|
png.addAll(
|
||||||
generateIhdr(
|
generateIhdr(
|
||||||
ihdr,
|
ihdrOfApng,
|
||||||
width,
|
width,
|
||||||
height
|
height
|
||||||
).asList()
|
).asList()
|
||||||
|
@ -259,19 +274,39 @@ class ApngDecoder {
|
||||||
|
|
||||||
|
|
||||||
png = ArrayList()
|
png = ArrayList()
|
||||||
val fcTL = fcTL()
|
|
||||||
fcTL.parse(byteArray)
|
// PARSE FCTL
|
||||||
delay = fcTL.delay
|
// Get the width of the png
|
||||||
yOffset = fcTL.yOffset
|
val width = Utils.uIntFromBytesBigEndian(byteArray.copyOfRange(i + 8, i + 12).map(Byte::toInt))
|
||||||
xOffset = fcTL.xOffset
|
// Get the height of the png
|
||||||
blendOp = fcTL.blendOp
|
val height = Utils.uIntFromBytesBigEndian(byteArray.copyOfRange(i + 12, i + 16).map(Byte::toInt))
|
||||||
disposeOp = fcTL.disposeOp
|
/*
|
||||||
val width = fcTL.pngWidth
|
* The `delay_num` and `delay_den` parameters together specify a fraction indicating the time to display the current frame, in seconds.
|
||||||
val height = fcTL.pngHeight
|
* If the the value of the numerator is 0 the decoder should render the next frame as quickly as possible, though viewers may impose a reasonable lower bound.
|
||||||
|
*/
|
||||||
|
// Get delay numerator
|
||||||
|
val delayNum = Utils.uShortFromBytesBigEndian(byteArray.copyOfRange(i + 24, i + 26).map(Byte::toInt)).toFloat()
|
||||||
|
// Get delay denominator
|
||||||
|
var delayDen = Utils.uShortFromBytesBigEndian(byteArray.copyOfRange(i + 26, i + 28).map(Byte::toInt)).toFloat()
|
||||||
|
|
||||||
|
// If the denominator is 0, it is to be treated as if it were 100 (that is, `delay_num` then specifies 1/100ths of a second).
|
||||||
|
if (delayDen == 0f) {
|
||||||
|
delayDen = 100f
|
||||||
|
}
|
||||||
|
|
||||||
|
delay = (delayNum / delayDen * 1000)
|
||||||
|
|
||||||
|
// Get x and y offsets
|
||||||
|
xOffset = Utils.uIntFromBytesBigEndian(byteArray.copyOfRange(i + 16, i + 20).map(Byte::toInt))
|
||||||
|
yOffset = Utils.uIntFromBytesBigEndian(byteArray.copyOfRange(i + 20, i + 24).map(Byte::toInt))
|
||||||
|
blendOp = Utils.decodeBlendOp(byteArray[33].toInt())
|
||||||
|
disposeOp = Utils.decodeDisposeOp(byteArray[32].toInt())
|
||||||
|
|
||||||
|
|
||||||
png.addAll(Utils.pngSignature.asList())
|
png.addAll(Utils.pngSignature.asList())
|
||||||
png.addAll(
|
png.addAll(
|
||||||
generateIhdr(
|
generateIhdr(
|
||||||
ihdr,
|
ihdrOfApng,
|
||||||
width,
|
width,
|
||||||
height
|
height
|
||||||
).asList()
|
).asList()
|
||||||
|
@ -395,7 +430,7 @@ class ApngDecoder {
|
||||||
cover.addAll(Utils.pngSignature.asList())
|
cover.addAll(Utils.pngSignature.asList())
|
||||||
cover.addAll(
|
cover.addAll(
|
||||||
generateIhdr(
|
generateIhdr(
|
||||||
ihdr,
|
ihdrOfApng,
|
||||||
maxWidth,
|
maxWidth,
|
||||||
maxHeight
|
maxHeight
|
||||||
).asList()
|
).asList()
|
||||||
|
@ -458,9 +493,14 @@ class ApngDecoder {
|
||||||
tnrs = byteArray
|
tnrs = byteArray
|
||||||
}
|
}
|
||||||
name.contentEquals(Utils.IHDR) -> {
|
name.contentEquals(Utils.IHDR) -> {
|
||||||
ihdr.parse(byteArray)
|
// Get length of the body of the chunk
|
||||||
maxWidth = ihdr.pngWidth
|
val bodySize = Utils.uIntFromBytesBigEndian(byteArray.copyOfRange(i - 4, i).map(Byte::toInt))
|
||||||
maxHeight = ihdr.pngHeight
|
// Get the width of the png
|
||||||
|
maxWidth = Utils.uIntFromBytesBigEndian(byteArray.copyOfRange(i +4, i + 8).map(Byte::toInt))
|
||||||
|
// Get the height of the png
|
||||||
|
maxHeight = Utils.uIntFromBytesBigEndian(byteArray.copyOfRange(i +8, i +12).map(Byte::toInt))
|
||||||
|
ihdrOfApng = byteArray.copyOfRange(i + 4, i + bodySize + 4)
|
||||||
|
|
||||||
buffer = Bitmap.createBitmap(
|
buffer = Bitmap.createBitmap(
|
||||||
maxWidth,
|
maxWidth,
|
||||||
maxHeight,
|
maxHeight,
|
||||||
|
@ -854,13 +894,12 @@ class ApngDecoder {
|
||||||
* @param height The height of the frame.
|
* @param height The height of the frame.
|
||||||
* @return [ByteArray] The generated IHDR.
|
* @return [ByteArray] The generated IHDR.
|
||||||
*/
|
*/
|
||||||
// TODO REMOVE IHDR
|
private fun generateIhdr(ihdrOfApng: ByteArray, width: Int, height: Int): ByteArray {
|
||||||
private fun generateIhdr(ihdrOfApng: IHDR, width: Int, height: Int): ByteArray {
|
|
||||||
val ihdr = ArrayList<Byte>()
|
val ihdr = ArrayList<Byte>()
|
||||||
// We need a body var to know body length and generate crc
|
// We need a body var to know body length and generate crc
|
||||||
val ihdrBody = ArrayList<Byte>()
|
val ihdrBody = ArrayList<Byte>()
|
||||||
// Add chunk body length
|
// Add chunk body length
|
||||||
ihdr.addAll(Utils.uIntToByteArray(ihdrOfApng.body.size).asList())
|
ihdr.addAll(Utils.uIntToByteArray(ihdrOfApng.size).asList())
|
||||||
// Add IHDR
|
// Add IHDR
|
||||||
ihdrBody.addAll(
|
ihdrBody.addAll(
|
||||||
arrayOf(
|
arrayOf(
|
||||||
|
@ -875,7 +914,7 @@ class ApngDecoder {
|
||||||
ihdrBody.addAll(Utils.uIntToByteArray(height).asList())
|
ihdrBody.addAll(Utils.uIntToByteArray(height).asList())
|
||||||
// Add complicated stuff like depth color ...
|
// Add complicated stuff like depth color ...
|
||||||
// If you want correct png you need same parameters. Good solution is to create new png.
|
// If you want correct png you need same parameters. Good solution is to create new png.
|
||||||
ihdrBody.addAll(ihdrOfApng.body.copyOfRange(8, 13).asList())
|
ihdrBody.addAll(ihdrOfApng.copyOfRange(8, 13).asList())
|
||||||
// Generate CRC
|
// Generate CRC
|
||||||
val crC32 = CRC32()
|
val crC32 = CRC32()
|
||||||
crC32.update(ihdrBody.toByteArray(), 0, ihdrBody.size)
|
crC32.update(ihdrBody.toByteArray(), 0, ihdrBody.size)
|
||||||
|
|
Loading…
Reference in New Issue