bitmapのrecycle漏れを修正

This commit is contained in:
tateisu 2018-01-30 21:28:01 +09:00
parent 2b2f693317
commit d57bd836a2
2 changed files with 33 additions and 32 deletions

View File

@ -26,6 +26,6 @@ interface ApngDecoderCallback {
// called when APNG Frame Control is detected and its bitmap was rendered. // called when APNG Frame Control is detected and its bitmap was rendered.
// its bitmap may same to default image for first frame. // its bitmap may same to default image for first frame.
// ( in this case, both of onDefaultImage and onAnimationFrame are called for same bitmap) // ( in this case, both of onDefaultImage and onAnimationFrame are called for same bitmap)
fun onAnimationFrame(apng : Apng, frameControl : ApngFrameControl, bitmap : ApngBitmap) fun onAnimationFrame(apng : Apng, frameControl : ApngFrameControl, frameBitmap : ApngBitmap)
} }

View File

@ -36,8 +36,7 @@ class ApngFrames private constructor(
} }
// WARNING: ownership of "src" will be moved or recycled. // WARNING: ownership of "src" will be moved or recycled.
private fun scaleBitmap(src : Bitmap?, size_max : Int) : Bitmap? { private fun scaleBitmap(src : Bitmap, size_max : Int) : Bitmap {
if(src == null) return null
val wSrc = src.width val wSrc = src.width
val hSrc = src.height val hSrc = src.height
@ -71,7 +70,7 @@ class ApngFrames private constructor(
return b2 return b2
} }
private fun toBitmap(src : ApngBitmap) : Bitmap { private fun toAndroidBitmap(src : ApngBitmap) : Bitmap {
return Bitmap.createBitmap( return Bitmap.createBitmap(
src.colors, // int[] 配列 src.colors, // int[] 配列
0, // offset 0, // offset
@ -82,12 +81,8 @@ class ApngFrames private constructor(
) )
} }
private fun toBitmap(src : ApngBitmap, size_max : Int) : Bitmap? { private fun toAndroidBitmap(src : ApngBitmap, size_max : Int) : Bitmap {
return scaleBitmap( return scaleBitmap( toAndroidBitmap( src ), size_max )
toBitmap(
src
), size_max
)
} }
@Suppress("unused") @Suppress("unused")
@ -112,11 +107,11 @@ class ApngFrames private constructor(
private var header : ApngImageHeader? = null private var header : ApngImageHeader? = null
private var animationControl : ApngAnimationControl? = null private var animationControl : ApngAnimationControl? = null
val width : Int var width : Int =1
get() = Math.min( pixelSizeMax, header?.width ?: 1) private set
val height : Int var height : Int = 1
get() = Math.min( pixelSizeMax, header?.height ?: 1) private set
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
val numFrames : Int val numFrames : Int
@ -264,6 +259,9 @@ class ApngFrames private constructor(
override fun onHeader(apng : Apng, header : ApngImageHeader) { override fun onHeader(apng : Apng, header : ApngImageHeader) {
this.header = header this.header = header
} }
override fun onAnimationInfo( override fun onAnimationInfo(
@ -281,23 +279,24 @@ class ApngFrames private constructor(
} }
override fun onDefaultImage(apng : Apng, bitmap : ApngBitmap) { override fun onDefaultImage(apng : Apng, bitmap : ApngBitmap) {
val androidBitmap = toAndroidBitmap(bitmap, pixelSizeMax)
this.width = androidBitmap.width
this.height = androidBitmap.height
defaultImage?.recycle() defaultImage?.recycle()
defaultImage = toBitmap(bitmap, pixelSizeMax) defaultImage = androidBitmap
} }
override fun onAnimationFrame( override fun onAnimationFrame(
apng : Apng, apng : Apng,
frameControl : ApngFrameControl, frameControl : ApngFrameControl,
bitmap : ApngBitmap frameBitmap : ApngBitmap
) { ) {
val frames = this.frames ?: return val frames = this.frames ?: return
val canvasBitmap = this.canvasBitmap ?: return val canvasBitmap = this.canvasBitmap ?: return
// APNGのフレーム画像をAndroidの形式に変換する。この段階ではリサイズしない
val bitmapNative = toBitmap(bitmap)
val previous : Bitmap? = if(frameControl.disposeOp == DisposeOp.Previous) { val previous : Bitmap? = if(frameControl.disposeOp == DisposeOp.Previous) {
// Capture the current bitmap region IF it needs to be reverted after rendering // Capture the current frameBitmap region IF it needs to be reverted after rendering
Bitmap.createBitmap( Bitmap.createBitmap(
canvasBitmap, canvasBitmap,
frameControl.xOffset, frameControl.xOffset,
@ -315,30 +314,32 @@ class ApngFrames private constructor(
null // (for blend, leave paint null) null // (for blend, leave paint null)
} }
// APNGのフレーム画像をAndroidの形式に変換する。この段階ではリサイズしない
val frameBitmapAndroid = toAndroidBitmap(frameBitmap)
// Draw the new frame into place // Draw the new frame into place
canvas.drawBitmap( canvas.drawBitmap(
bitmapNative, frameBitmapAndroid,
frameControl.xOffset.toFloat(), frameControl.xOffset.toFloat(),
frameControl.yOffset.toFloat(), frameControl.yOffset.toFloat(),
paint paint
) )
// Extract a drawable from the canvas. Have to copy the current bitmap. frameBitmapAndroid.recycle()
// Extract a drawable from the canvas. Have to copy the current frameBitmap.
// Store the drawable in the sequence of frames // Store the drawable in the sequence of frames
val timeStart = timeTotal val timeStart = timeTotal
val timeWidth = Math.max(1L, frameControl.delayMilliseconds) val timeWidth = Math.max(1L, frameControl.delayMilliseconds)
timeTotal += timeWidth timeTotal += timeWidth
val scaledBitmap = val scaledBitmap = scaleBitmap(
scaleBitmap( canvasBitmap.copy( Bitmap.Config.ARGB_8888, false ),
canvasBitmap.copy( pixelSizeMax
Bitmap.Config.ARGB_8888, )
false
), pixelSizeMax frames.add(Frame(scaledBitmap, timeStart, timeWidth))
)
if(scaledBitmap != null) {
frames.add(Frame(scaledBitmap, timeStart, timeWidth))
}
// Now "dispose" of the frame in preparation for the next. // Now "dispose" of the frame in preparation for the next.
// https://wiki.mozilla.org/APNG_Specification#.60fcTL.60:_The_Frame_Control_Chunk // https://wiki.mozilla.org/APNG_Specification#.60fcTL.60:_The_Frame_Control_Chunk