square / gifencoder

A pure Java library implementing the GIF89a specification. Suitable for use on Android.
Apache License 2.0
666 stars 75 forks source link

How to convert bitmap to double-dimension array efficiently #22

Closed vince-styling closed 2 years ago

vince-styling commented 2 years ago

01-21 14:18:55.945 32380 20665 I HighQualityGif2: start frame:1

01-21 14:18:56.164 32380 20624 I frameextractio: Background concurrent copying GC freed 1475072(51MB) AllocSpace objects, 6(4180KB) LOS objects, 38% free, 38MB/62MB, paused 31us total 181.235ms 01-21 14:18:57.072 32380 20624 I frameextractio: Background young concurrent copying GC freed 30721(13MB) AllocSpace objects, 0(0B) LOS objects, 15% free, 53MB/62MB, paused 137us total 105.239ms 01-21 14:18:57.454 32380 20624 I frameextractio: Background concurrent copying GC freed 288180(18MB) AllocSpace objects, 0(0B) LOS objects, 33% free, 48MB/72MB, paused 383us total 149.623ms 01-21 14:18:58.822 32380 20624 I frameextractio: Background concurrent copying GC freed 1545134(51MB) AllocSpace objects, 0(0B) LOS objects, 23% free, 77MB/101MB, paused 36us total 144.059ms

01-21 14:19:13.774 32380 20665 I HighQualityGif2: end frame:1

I found convert bitmap to array was too slow and took many memory, above is the log for me, it took about 20s and cause gc multiple times, my device isn't old, android 11.

private fun convertTo2D(bitmap: Bitmap): Array<IntArray> {
    val w = bitmap.width
    val h = bitmap.height
    val argb = getPixels(bitmap)
    val twoD = Array(h) { IntArray(w) }
    convertTo2D(argb, w, h, twoD)
    return twoD
}

private fun convertTo2D(argb: IntArray, srcWidth: Int, srcHeight: Int, dest: Array<IntArray>) {
    for (i in 0 until srcHeight) {
        for (j in 0 until srcWidth) {
            dest[i][j] = argb[i * srcWidth + j]
        }
    }
}

private fun getPixels(bitmap: Bitmap): IntArray {
    val w = bitmap.width
    val h = bitmap.height
    val pixels = IntArray(w * h)
    bitmap.getPixels(pixels, 0, w, 0, 0, w, h)
    return pixels
}

MLog.info(TAG, "start frame:$index")
gifEncoder.addImage(convertTo2D(bitmap), options)
MLog.info(TAG, "end frame:$index")

the output gif can be play as expected, just too cost

vince-styling commented 2 years ago

wasn't convert to array cost but gifEncoder.addImage(), I trace into and found the most time consume on FloydSteinbergDitherer#dither() method

cp-radhika-s commented 1 year ago

facing the same issue. any solution for this?

vince-styling commented 1 year ago

this library only for demenstraction, never concern about performance, I already turn to another