リファクタ
This commit is contained in:
parent
84383661d8
commit
8c46295631
|
@ -4,7 +4,6 @@ package jp.juggler.apng
|
|||
|
||||
import jp.juggler.apng.util.ByteSequence
|
||||
|
||||
|
||||
class ApngAnimationControl internal constructor(src : ByteSequence) {
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -20,12 +20,14 @@ class ApngBackground internal constructor(colorType: ColorType, src: ByteSequenc
|
|||
blue = v
|
||||
index = - 1
|
||||
}
|
||||
|
||||
ColorType.RGB, ColorType.RGBA -> {
|
||||
red = src.readUInt16()
|
||||
green = src.readUInt16()
|
||||
blue = src.readUInt16()
|
||||
index = - 1
|
||||
}
|
||||
|
||||
ColorType.INDEX -> {
|
||||
red = - 1
|
||||
green = - 1
|
||||
|
|
|
@ -11,7 +11,7 @@ class ApngBitmap(var width : Int, var height : Int) {
|
|||
fun reset(width : Int, height : Int) {
|
||||
val newSize = width * height
|
||||
if(newSize > colors.size)
|
||||
throw ParseError("can't resize to $width x $height , it's greater than initial size")
|
||||
throw ApngParseError("can't resize to $width x $height , it's greater than initial size")
|
||||
this.width = width
|
||||
this.height = height
|
||||
// 透明な黒で初期化する
|
||||
|
@ -24,11 +24,7 @@ class ApngBitmap(var width : Int, var height : Int) {
|
|||
private var pos : Int = 0
|
||||
var step : Int = 1
|
||||
|
||||
fun setPixel(argb : Int) : Pointer {
|
||||
// if( pos == width) println("setPixel 0x%x".format(argb))
|
||||
colors[pos] = argb
|
||||
return this
|
||||
}
|
||||
fun setPixel(argb : Int) = apply { colors[pos] = argb }
|
||||
|
||||
fun setPixel(a : Int, r : Int, g : Int, b : Int) = setPixel(
|
||||
((a and 255) shl 24) or
|
||||
|
@ -37,18 +33,14 @@ class ApngBitmap(var width : Int, var height : Int) {
|
|||
(b and 255)
|
||||
)
|
||||
|
||||
fun setOffset(pos : Int = 0, step : Int = 1) : Pointer {
|
||||
fun setOffset(pos : Int = 0, step : Int = 1) = apply {
|
||||
this.pos = pos
|
||||
this.step = step
|
||||
return this
|
||||
}
|
||||
|
||||
fun setXY(x : Int, y : Int, step : Int = 1) = setOffset(x + y * width, step)
|
||||
|
||||
fun plus(x : Int) : Pointer {
|
||||
pos += x
|
||||
return this
|
||||
}
|
||||
fun plus(x : Int) = apply { pos += x }
|
||||
|
||||
fun next() = plus(step)
|
||||
|
||||
|
|
|
@ -23,17 +23,17 @@ internal class ApngChunk(crc32:CRC32,tokenizer: StreamTokenizer) {
|
|||
|
||||
crc32.update(bytes, 0, size)
|
||||
val crcActual = crc32.value
|
||||
if (crcActual != crcExpect) throw ParseError("CRC not match.")
|
||||
if(crcActual != crcExpect) throw ApngParseError("CRC not match.")
|
||||
|
||||
return bytes
|
||||
}
|
||||
|
||||
fun skipBody(tokenizer: StreamTokenizer) {
|
||||
fun skipBody(tokenizer : StreamTokenizer) =
|
||||
tokenizer.skipBytes((size + 4).toLong())
|
||||
}
|
||||
|
||||
|
||||
fun checkCRC(tokenizer : StreamTokenizer, crcActual : Long) {
|
||||
val crcExpect = tokenizer.readUInt32()
|
||||
if (crcActual != crcExpect) throw ParseError("CRC not match.")
|
||||
if(crcActual != crcExpect) throw ApngParseError("CRC not match.")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,22 +11,22 @@ object ApngDecoder {
|
|||
private val PNG_SIGNATURE = byteArrayOf(0x89.toByte(), 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0a)
|
||||
|
||||
fun parseStream(
|
||||
_inStream : InputStream,
|
||||
inStream : InputStream,
|
||||
callback : ApngDecoderCallback
|
||||
) {
|
||||
val apng = Apng()
|
||||
val tokenizer = StreamTokenizer(_inStream)
|
||||
val tokenizer = StreamTokenizer(inStream)
|
||||
|
||||
val pngHeader = tokenizer.readBytes(8)
|
||||
if(! pngHeader.contentEquals(PNG_SIGNATURE)) {
|
||||
throw ParseError("header not match")
|
||||
throw ApngParseError("header not match")
|
||||
}
|
||||
|
||||
var lastSequenceNumber : Int? = null
|
||||
fun checkSequenceNumber(n : Int) {
|
||||
val last = lastSequenceNumber
|
||||
if(last != null && n <= last) {
|
||||
throw ParseError("incorrect sequenceNumber. last=$lastSequenceNumber,current=$n")
|
||||
throw ApngParseError("incorrect sequenceNumber. last=$lastSequenceNumber,current=$n")
|
||||
}
|
||||
lastSequenceNumber = n
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ object ApngDecoder {
|
|||
"PLTE" -> apng.palette = ApngPalette(chunk.readBody(crc32, tokenizer))
|
||||
|
||||
"bKGD" -> {
|
||||
val header = apng.header ?: throw ParseError("missing IHDR")
|
||||
val header = apng.header ?: throw ApngParseError("missing IHDR")
|
||||
apng.background = ApngBackground(
|
||||
header.colorType,
|
||||
ByteSequence(chunk.readBody(crc32, tokenizer))
|
||||
|
@ -64,7 +64,7 @@ object ApngDecoder {
|
|||
}
|
||||
|
||||
"tRNS" -> {
|
||||
val header = apng.header ?: throw ParseError("missing IHDR")
|
||||
val header = apng.header ?: throw ApngParseError("missing IHDR")
|
||||
val body = chunk.readBody(crc32, tokenizer)
|
||||
when(header.colorType) {
|
||||
ColorType.GREY -> apng.transparentColor =
|
||||
|
@ -72,15 +72,15 @@ object ApngDecoder {
|
|||
ColorType.RGB -> apng.transparentColor =
|
||||
ApngTransparentColor(false, ByteSequence(body))
|
||||
ColorType.INDEX -> apng.palette?.parseTRNS(body)
|
||||
?: throw ParseError("missing palette")
|
||||
?: throw ApngParseError("missing palette")
|
||||
else -> callback.onApngWarning("tRNS ignored. colorType =${header.colorType}")
|
||||
}
|
||||
}
|
||||
|
||||
"IDAT" -> {
|
||||
val header = apng.header ?: throw ParseError("missing IHDR")
|
||||
val header = apng.header ?: throw ApngParseError("missing IHDR")
|
||||
if(idatDecoder == null) {
|
||||
bitmap ?: throw ParseError("missing bitmap")
|
||||
bitmap ?: throw ApngParseError("missing bitmap")
|
||||
bitmap.reset(header.width, header.height)
|
||||
idatDecoder = IdatDecoder(
|
||||
apng,
|
||||
|
@ -106,7 +106,7 @@ object ApngDecoder {
|
|||
}
|
||||
|
||||
"acTL" -> {
|
||||
val header = apng.header ?: throw ParseError("missing IHDR")
|
||||
val header = apng.header ?: throw ApngParseError("missing IHDR")
|
||||
val animationControl =
|
||||
ApngAnimationControl(ByteSequence(chunk.readBody(crc32, tokenizer)))
|
||||
apng.animationControl = animationControl
|
||||
|
@ -121,9 +121,9 @@ object ApngDecoder {
|
|||
}
|
||||
|
||||
"fdAT" -> {
|
||||
val fctl = lastFctl ?: throw ParseError("missing fCTL before fdAT")
|
||||
val fctl = lastFctl ?: throw ApngParseError("missing fCTL before fdAT")
|
||||
if(fdatDecoder == null) {
|
||||
bitmap ?: throw ParseError("missing bitmap")
|
||||
bitmap ?: throw ApngParseError("missing bitmap")
|
||||
bitmap.reset(fctl.width, fctl.height)
|
||||
fdatDecoder = IdatDecoder(
|
||||
apng,
|
||||
|
|
|
@ -4,7 +4,6 @@ package jp.juggler.apng
|
|||
|
||||
import jp.juggler.apng.util.ByteSequence
|
||||
|
||||
|
||||
class ApngFrameControl internal constructor(src : ByteSequence) {
|
||||
|
||||
val width : Int
|
||||
|
@ -33,7 +32,8 @@ class ApngFrameControl internal constructor(src: ByteSequence) {
|
|||
blendOp = BlendOp.values().first { it.num == num }
|
||||
}
|
||||
|
||||
override fun toString() ="ApngFrameControl(width=$width,height=$height,x=$xOffset,y=$yOffset,delayNum=$delayNum,delayDen=$delayDen,disposeOp=$disposeOp,blendOp=$blendOp)"
|
||||
override fun toString() =
|
||||
"ApngFrameControl(width=$width,height=$height,x=$xOffset,y=$yOffset,delayNum=$delayNum,delayDen=$delayDen,disposeOp=$disposeOp,blendOp=$blendOp)"
|
||||
|
||||
val delayMilliseconds : Long
|
||||
get() = when(delayDen) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import jp.juggler.apng.util.ByteSequence
|
|||
|
||||
// information from IHDR chunk.
|
||||
class ApngImageHeader internal constructor(src : ByteSequence) {
|
||||
|
||||
val width : Int
|
||||
val height : Int
|
||||
val bitDepth : Int
|
||||
|
@ -18,7 +19,7 @@ class ApngImageHeader internal constructor(src: ByteSequence) {
|
|||
|
||||
width = src.readInt32()
|
||||
height = src.readInt32()
|
||||
if(width <=0 || height <=0 ) throw ParseError("w=$width,h=$height is too small")
|
||||
if(width <= 0 || height <= 0) throw ApngParseError("w=$width,h=$height is too small")
|
||||
|
||||
bitDepth = src.readUInt8()
|
||||
|
||||
|
@ -37,5 +38,6 @@ class ApngImageHeader internal constructor(src: ByteSequence) {
|
|||
interlaceMethod = InterlaceMethod.values().first { it.num == num }
|
||||
}
|
||||
|
||||
override fun toString() = "ApngImageHeader(w=$width,h=$height,bits=$bitDepth,color=$colorType,interlace=$interlaceMethod)"
|
||||
override fun toString() =
|
||||
"ApngImageHeader(w=$width,h=$height,bits=$bitDepth,color=$colorType,interlace=$interlaceMethod)"
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import jp.juggler.apng.util.getUInt8
|
|||
class ApngPalette(
|
||||
src : ByteArray // repeat of R,G,B
|
||||
) {
|
||||
|
||||
companion object {
|
||||
// full opaque black
|
||||
const val OPAQUE = 255 shl 24
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
package jp.juggler.apng
|
||||
|
||||
class ApngParseError(message: String) : IllegalArgumentException(message)
|
|
@ -8,6 +8,7 @@ class ApngTransparentColor internal constructor(isGreyScale:Boolean, src: ByteSe
|
|||
val red : Int
|
||||
val green : Int
|
||||
val blue : Int
|
||||
|
||||
init {
|
||||
if(isGreyScale) {
|
||||
val v = src.readUInt16()
|
||||
|
|
|
@ -4,7 +4,6 @@ package jp.juggler.apng
|
|||
|
||||
import jp.juggler.apng.util.*
|
||||
import java.io.InputStream
|
||||
import java.util.*
|
||||
import java.util.zip.CRC32
|
||||
import java.util.zip.Inflater
|
||||
|
||||
|
@ -33,7 +32,6 @@ internal class IdatDecoder(
|
|||
|
||||
private val dummyPaletteData = IntArray(0)
|
||||
|
||||
|
||||
private fun abs(v : Int) = if(v >= 0) v else - v
|
||||
|
||||
// a = left, b = above, c = upper left
|
||||
|
@ -51,8 +49,9 @@ internal class IdatDecoder(
|
|||
|
||||
private inline fun scanLine1(baLine : ByteArray, pass_w : Int, block : (v : Int) -> Unit) {
|
||||
var pos = 1
|
||||
var x = 0
|
||||
while(pass_w - x >= 8) {
|
||||
var remain = pass_w
|
||||
while(remain >= 8) {
|
||||
remain -= 8
|
||||
val v = baLine[pos ++].toInt()
|
||||
block((v shr 7) and 1)
|
||||
block((v shr 6) and 1)
|
||||
|
@ -62,9 +61,7 @@ internal class IdatDecoder(
|
|||
block((v shr 2) and 1)
|
||||
block((v shr 1) and 1)
|
||||
block(v and 1)
|
||||
x += 8
|
||||
}
|
||||
val remain = pass_w - x
|
||||
if(remain > 0) {
|
||||
val v = baLine[pos].toInt()
|
||||
block((v shr 7) and 1)
|
||||
|
@ -79,16 +76,15 @@ internal class IdatDecoder(
|
|||
|
||||
private inline fun scanLine2(baLine : ByteArray, pass_w : Int, block : (v : Int) -> Unit) {
|
||||
var pos = 1
|
||||
var x = 0
|
||||
while(pass_w - x >= 4) {
|
||||
var remain = pass_w
|
||||
while(remain >= 4) {
|
||||
remain -= 4
|
||||
val v = baLine[pos ++].toInt()
|
||||
block((v shr 6) and 3)
|
||||
block((v shr 4) and 3)
|
||||
block((v shr 2) and 3)
|
||||
block(v and 3)
|
||||
x += 4
|
||||
}
|
||||
val remain = pass_w - x
|
||||
if(remain > 0) {
|
||||
val v = baLine[pos].toInt()
|
||||
block((v shr 6) and 3)
|
||||
|
@ -99,14 +95,13 @@ internal class IdatDecoder(
|
|||
|
||||
private inline fun scanLine4(baLine : ByteArray, pass_w : Int, block : (v : Int) -> Unit) {
|
||||
var pos = 1
|
||||
var x = 0
|
||||
while(pass_w - x >= 2) {
|
||||
var remain = pass_w
|
||||
while(remain >= 2) {
|
||||
remain -= 2
|
||||
val v = baLine[pos ++].toInt()
|
||||
block((v shr 4) and 15)
|
||||
block(v and 15)
|
||||
x += 2
|
||||
}
|
||||
val remain = pass_w - x
|
||||
if(remain > 0) {
|
||||
val v = baLine[pos].toInt()
|
||||
block((v shr 4) and 15)
|
||||
|
@ -115,14 +110,16 @@ internal class IdatDecoder(
|
|||
|
||||
private inline fun scanLine8(baLine : ByteArray, pass_w : Int, block : (v : Int) -> Unit) {
|
||||
var pos = 1
|
||||
for(x in 0 until pass_w) {
|
||||
var remain = pass_w
|
||||
while(remain -- > 0) {
|
||||
block(baLine.getUInt8(pos ++))
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun scanLine16(baLine : ByteArray, pass_w : Int, block : (v : Int) -> Unit) {
|
||||
var pos = 1
|
||||
for(x in 0 until pass_w) {
|
||||
var remain = pass_w
|
||||
while(remain -- > 0) {
|
||||
block(baLine.getUInt16(pos))
|
||||
pos += 2
|
||||
}
|
||||
|
@ -134,7 +131,8 @@ internal class IdatDecoder(
|
|||
block : (r : Int, g : Int, b : Int) -> Unit
|
||||
) {
|
||||
var pos = 1
|
||||
for(x in 0 until pass_w) {
|
||||
var remain = pass_w
|
||||
while(remain -- > 0) {
|
||||
block(
|
||||
baLine.getUInt8(pos),
|
||||
baLine.getUInt8(pos + 1),
|
||||
|
@ -150,7 +148,8 @@ internal class IdatDecoder(
|
|||
block : (r : Int, g : Int, b : Int) -> Unit
|
||||
) {
|
||||
var pos = 1
|
||||
for(x in 0 until pass_w) {
|
||||
var remain = pass_w
|
||||
while(remain -- > 0) {
|
||||
block(
|
||||
baLine.getUInt16(pos),
|
||||
baLine.getUInt16(pos + 2),
|
||||
|
@ -166,7 +165,8 @@ internal class IdatDecoder(
|
|||
block : (r : Int, g : Int, b : Int, a : Int) -> Unit
|
||||
) {
|
||||
var pos = 1
|
||||
for(x in 0 until pass_w) {
|
||||
var remain = pass_w
|
||||
while(remain -- > 0) {
|
||||
block(
|
||||
baLine.getUInt8(pos),
|
||||
baLine.getUInt8(pos + 1),
|
||||
|
@ -183,7 +183,8 @@ internal class IdatDecoder(
|
|||
block : (r : Int, g : Int, b : Int, a : Int) -> Unit
|
||||
) {
|
||||
var pos = 1
|
||||
for(x in 0 until pass_w) {
|
||||
var remain = pass_w
|
||||
while(remain -- > 0) {
|
||||
block(
|
||||
baLine.getUInt16(pos),
|
||||
baLine.getUInt16(pos + 2),
|
||||
|
@ -200,7 +201,8 @@ internal class IdatDecoder(
|
|||
block : (g : Int, a : Int) -> Unit
|
||||
) {
|
||||
var pos = 1
|
||||
for(x in 0 until pass_w) {
|
||||
var remain = pass_w
|
||||
while(remain -- > 0) {
|
||||
block(
|
||||
baLine.getUInt8(pos),
|
||||
baLine.getUInt8(pos + 1)
|
||||
|
@ -215,7 +217,8 @@ internal class IdatDecoder(
|
|||
block : (g : Int, a : Int) -> Unit
|
||||
) {
|
||||
var pos = 1
|
||||
for(x in 0 until pass_w) {
|
||||
var remain = pass_w
|
||||
while(remain -- > 0) {
|
||||
block(
|
||||
baLine.getUInt16(pos),
|
||||
baLine.getUInt16(pos + 2)
|
||||
|
@ -233,7 +236,7 @@ internal class IdatDecoder(
|
|||
private val sampleBits : Int
|
||||
private val sampleBytes : Int
|
||||
private val scanLineBytesMax : Int
|
||||
private val linePool = LinkedList<ByteArray>()
|
||||
private val scanLinePool : BufferPool
|
||||
private val transparentCheckerGrey : (v : Int) -> Int
|
||||
private val transparentCheckerRGB : (r : Int, g : Int, b : Int) -> Int
|
||||
private val renderScanLineFunc : (baLine : ByteArray) -> Unit
|
||||
|
@ -250,15 +253,8 @@ internal class IdatDecoder(
|
|||
|
||||
init {
|
||||
val header = requireNotNull(apng.header)
|
||||
this.colorType = header.colorType
|
||||
this.bitDepth = header.bitDepth
|
||||
|
||||
this.paletteData = if(colorType == ColorType.INDEX) {
|
||||
apng.palette?.list
|
||||
?: throw ParseError("missing ApngPalette for index color")
|
||||
} else {
|
||||
dummyPaletteData
|
||||
}
|
||||
colorType = header.colorType
|
||||
bitDepth = header.bitDepth
|
||||
|
||||
sampleBits = when(colorType) {
|
||||
ColorType.GREY, ColorType.INDEX -> bitDepth
|
||||
|
@ -269,9 +265,14 @@ internal class IdatDecoder(
|
|||
|
||||
sampleBytes = (sampleBits + 7) / 8
|
||||
scanLineBytesMax = 1 + (bitmap.width * sampleBits + 7) / 8
|
||||
scanLinePool = BufferPool(scanLineBytesMax)
|
||||
|
||||
linePool.add(ByteArray(scanLineBytesMax))
|
||||
linePool.add(ByteArray(scanLineBytesMax))
|
||||
paletteData = if(colorType == ColorType.INDEX) {
|
||||
apng.palette?.list
|
||||
?: throw ApngParseError("missing ApngPalette for index color")
|
||||
} else {
|
||||
dummyPaletteData
|
||||
}
|
||||
|
||||
val transparentColor = apng.transparentColor
|
||||
|
||||
|
@ -400,7 +401,7 @@ internal class IdatDecoder(
|
|||
}
|
||||
|
||||
private fun colorBitsNotSupported() : Nothing {
|
||||
throw ParseError("bitDepth $bitDepth is not supported for $colorType")
|
||||
throw ApngParseError("bitDepth $bitDepth is not supported for $colorType")
|
||||
}
|
||||
|
||||
private fun selectRenderFunc() = when(colorType) {
|
||||
|
@ -443,7 +444,7 @@ internal class IdatDecoder(
|
|||
passY = 0
|
||||
scanLineBytes = 1 + (passWidth * sampleBits + 7) / 8
|
||||
|
||||
baPreviousLine?.let { linePool.add(it) }
|
||||
scanLinePool.recycle(baPreviousLine)
|
||||
baPreviousLine = null
|
||||
|
||||
if(passWidth <= 0 || passHeight <= 0) {
|
||||
|
@ -470,7 +471,7 @@ internal class IdatDecoder(
|
|||
return false
|
||||
}
|
||||
|
||||
val baLine = linePool.removeFirst()
|
||||
val baLine = scanLinePool.obtain()
|
||||
inflateBufferQueue.readBytes(baLine, 0, scanLineBytes)
|
||||
|
||||
val filterNum = baLine.getUInt8(0)
|
||||
|
@ -488,7 +489,6 @@ internal class IdatDecoder(
|
|||
val leftPos = pos - sampleBytes
|
||||
val vLeft = if(leftPos <= 0) 0 else baLine.getUInt8(leftPos)
|
||||
|
||||
|
||||
baLine[pos] = (vCur + vLeft).toByte()
|
||||
|
||||
// if( callback.canApngDebug() ){
|
||||
|
@ -550,7 +550,7 @@ internal class IdatDecoder(
|
|||
renderScanLineFunc(baLine)
|
||||
|
||||
// save previous line
|
||||
baPreviousLine?.let { linePool.add(it) }
|
||||
scanLinePool.recycle(baPreviousLine)
|
||||
baPreviousLine = baLine
|
||||
|
||||
if(++ passY >= passHeight) {
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
package jp.juggler.apng
|
||||
|
||||
class ParseError(message: String) : IllegalArgumentException(message)
|
|
@ -4,12 +4,6 @@ import java.util.*
|
|||
|
||||
internal class BufferPool(private val arraySize : Int) {
|
||||
private val list = LinkedList<ByteArray>()
|
||||
|
||||
fun recycle(array: ByteArray) {
|
||||
list.add( array)
|
||||
}
|
||||
|
||||
fun obtain(): ByteArray {
|
||||
return if( list.isEmpty() ) ByteArray(arraySize) else list.removeFirst()
|
||||
}
|
||||
fun obtain() : ByteArray = if(list.isEmpty()) ByteArray(arraySize) else list.removeFirst()
|
||||
fun recycle(array : ByteArray?) = array?.let { list.add(it) }
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package jp.juggler.apng.util
|
||||
|
||||
import jp.juggler.apng.ParseError
|
||||
import jp.juggler.apng.ApngParseError
|
||||
|
||||
internal fun ByteArray.getUInt8(pos : Int) = get(pos).toInt() and 255
|
||||
|
||||
|
@ -16,10 +16,11 @@ internal class ByteSequence(
|
|||
var offset : Int,
|
||||
var length : Int
|
||||
) {
|
||||
|
||||
constructor(ba : ByteArray) : this(ba, 0, ba.size)
|
||||
|
||||
private inline fun <T> readX(dataSize : Int, block : () -> T) : T {
|
||||
if(length < dataSize) throw ParseError("readX: unexpected end")
|
||||
if(length < dataSize) throw ApngParseError("readX: unexpected end")
|
||||
val v = block()
|
||||
offset += dataSize
|
||||
length -= dataSize
|
||||
|
|
|
@ -9,16 +9,9 @@ internal class ByteSequenceQueue(private val bufferRecycler :(ByteSequence)->Uni
|
|||
val remain : Int
|
||||
get() = list.sumBy { it.length }
|
||||
|
||||
fun add(range: ByteSequence) {
|
||||
list.add(range)
|
||||
}
|
||||
fun add(range : ByteSequence) =list.add(range)
|
||||
|
||||
fun clear() {
|
||||
for( item in list ){
|
||||
bufferRecycler(item)
|
||||
}
|
||||
list.clear()
|
||||
}
|
||||
fun clear() = list.also{ it.forEach(bufferRecycler) }.clear()
|
||||
|
||||
fun readBytes(dst : ByteArray, offset : Int, length : Int) : Int {
|
||||
var dstOffset = offset
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package jp.juggler.apng.util
|
||||
|
||||
import jp.juggler.apng.ParseError
|
||||
import jp.juggler.apng.ApngParseError
|
||||
import java.io.InputStream
|
||||
import java.util.zip.CRC32
|
||||
|
||||
|
@ -12,7 +12,7 @@ internal class StreamTokenizer(val inStream: InputStream) {
|
|||
val remain = size - nRead
|
||||
if(remain <= 0) break
|
||||
val delta = inStream.skip(size - nRead)
|
||||
if (delta <= 0) throw ParseError("skipBytes: unexpected EoS")
|
||||
if(delta <= 0) throw ApngParseError("skipBytes: unexpected EoS")
|
||||
nRead += delta
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ internal class StreamTokenizer(val inStream: InputStream) {
|
|||
val remain = size - nRead
|
||||
if(remain <= 0) break
|
||||
val delta = inStream.read(dst, nRead, size - nRead)
|
||||
if (delta < 0) throw ParseError("readBytes: unexpected EoS")
|
||||
if(delta < 0) throw ApngParseError("readBytes: unexpected EoS")
|
||||
nRead += delta
|
||||
}
|
||||
return dst
|
||||
|
@ -32,7 +32,7 @@ internal class StreamTokenizer(val inStream: InputStream) {
|
|||
|
||||
private fun readByte() : Int {
|
||||
val b = inStream.read()
|
||||
if( b == -1 ) throw ParseError("readBytes: unexpected EoS")
|
||||
if(b == - 1) throw ApngParseError("readByte: unexpected EoS")
|
||||
return b and 0xff
|
||||
}
|
||||
|
||||
|
|
|
@ -24,11 +24,9 @@ class ApngFrames private constructor(
|
|||
private const val DELAY_AFTER_END = 3000L
|
||||
|
||||
// アニメーションフレームの描画に使う
|
||||
private val sPaintDontBlend : Paint by lazy {
|
||||
val paint = Paint()
|
||||
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC)
|
||||
paint.isFilterBitmap = true
|
||||
paint
|
||||
private val sPaintDontBlend = Paint().apply {
|
||||
xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC)
|
||||
isFilterBitmap = true
|
||||
}
|
||||
|
||||
private fun createBlankBitmap(w : Int, h : Int) =
|
||||
|
@ -45,7 +43,7 @@ class ApngFrames private constructor(
|
|||
|
||||
val wSrc = src.width
|
||||
val hSrc = src.height
|
||||
if(size_max <= 0 || wSrc <= size_max && hSrc <= size_max) {
|
||||
if(size_max <= 0 || (wSrc <= size_max && hSrc <= size_max)) {
|
||||
return if(recycleSrc) {
|
||||
src
|
||||
} else {
|
||||
|
@ -75,8 +73,8 @@ class ApngFrames private constructor(
|
|||
return b2
|
||||
}
|
||||
|
||||
private fun toAndroidBitmap(src : ApngBitmap) : Bitmap {
|
||||
return Bitmap.createBitmap(
|
||||
private fun toAndroidBitmap(src : ApngBitmap) =
|
||||
Bitmap.createBitmap(
|
||||
src.colors, // int[] 配列
|
||||
0, // offset
|
||||
src.width, //stride
|
||||
|
@ -84,7 +82,6 @@ class ApngFrames private constructor(
|
|||
src.height, //height
|
||||
Bitmap.Config.ARGB_8888
|
||||
)
|
||||
}
|
||||
|
||||
private fun toAndroidBitmap(src : ApngBitmap, size_max : Int) =
|
||||
scaleBitmap(size_max, toAndroidBitmap(src))
|
||||
|
@ -99,11 +96,8 @@ class ApngFrames private constructor(
|
|||
try {
|
||||
ApngDecoder.parseStream(inStream, result)
|
||||
result.onParseComplete()
|
||||
return if(result.defaultImage != null || result.frames?.isNotEmpty() == true) {
|
||||
result
|
||||
} else {
|
||||
throw RuntimeException("APNG has no image")
|
||||
}
|
||||
return result.takeIf { result.defaultImage != null || result.frames?.isNotEmpty() == true }
|
||||
?: throw RuntimeException("APNG has no image")
|
||||
} catch(ex : Throwable) {
|
||||
result.dispose()
|
||||
throw ex
|
||||
|
|
Loading…
Reference in New Issue