brmbrm
brmbrm

Reputation: 1

Converting a bitmap to bytearray to be displayed on an e-paper

so I have to convert a bitmap that is 400x300 into a byte array with exactly 15000 size. It has to be displayed on an e-paper screen so it can only be black/white/gray.

This is my attempt so far:

fun convertPictureToByteArray(bitmap: Bitmap): ByteArray {
        val byteArray = ByteArray(15000)
        var index = 0
        var temp = 0

        val pixels = IntArray(bitmap.width * bitmap.height)
        bitmap.getPixels(pixels, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)
        for(x in (bitmap.height - 1) downTo 0) {
            for(y in 0 until bitmap.width / 8) {
                var tempPixels = IntArray(8)
                for(z in 0 until 8) {
                    tempPixels[z] = pixels[temp]
                    temp++
                }
                var totalLuminance = 0.0
                for(pixel in tempPixels) {
                    val red = Color.red(pixel)
                    val green = Color.green(pixel)
                    val blue = Color.blue(pixel)

                    val luminance = 0.299 * red + 0.587 * green + 0.114 * blue
                    totalLuminance += luminance
                }

                val averageLuminance = totalLuminance / tempPixels.size
                byteArray[index] = grayShadesArray[averageLuminance.toInt()]
                index++
            }
        }

        return byteArray
    }

Basically what it should do is go through the bitmap pixel by pixel and get average luminance from 8 pixels that are next to each other. Based on the average luminance I get byte value from greyShadesArray with that index and save it to a byte array I return. It kinda works but not well enough. There are white lines and text is not readable: Converted image

Any suggestions on fixing it or other approaches are much appreciated!

Upvotes: 0

Views: 437

Answers (2)

Tenfour04
Tenfour04

Reputation: 93834

Just a suggestion to use bit manipulation instead of concatenating and parsing Strings. It should be significantly faster, considering you're running this for every pixel in an image. You can use the repeat function for more simply iterating a range where you don't need the iteration index variable. Also, there's a Color.luminance utility function.

fun convertPictureToByteArray(bitmap: Bitmap): ByteArray {
    val byteArray = ByteArray(15000)
    var index = 0
    var temp = 0

    val pixels = IntArray(bitmap.width * bitmap.height)
    bitmap.getPixels(pixels, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)
    repeat(pixels.size / 8) {
        var tempBinary = 0
        repeat(8) {
            tempBinary = (tempBinary shl 1) or Color.luminance(pixels[temp++]).roundToInt()
        }
        byteArray[index++] = tempBinary.toByte()
    }

    return byteArray
}

Upvotes: 0

brmbrm
brmbrm

Reputation: 1

As @Selvin suggested I should have checked each pixel by the treshold and converted the binary to hex/byte. Here is the working version:

fun convertPictureToByteArray(bitmap: Bitmap): ByteArray {
        val byteArray = ByteArray(15000)
        var index = 0
        var temp = 0

        val pixels = IntArray(bitmap.width * bitmap.height)
        bitmap.getPixels(pixels, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)
        for(x in (bitmap.height - 1) downTo 0) {
            for(y in 0 until bitmap.width / 8) {
                var tempBinary = ""
                for(z in 0 until 8) {
                    val red = Color.red(pixels[temp])
                    val green = Color.green(pixels[temp])
                    val blue = Color.blue(pixels[temp])

                    val luminance = 0.299 * red + 0.587 * green + 0.114 * blue
                    if(luminance < 128)
                        tempBinary += "0"
                    else
                        tempBinary += "1"
                    temp++
                }
                val decimalValue = Integer.parseInt(tempBinary, 2)
                val hexValue = decimalValue.toString(16).toUpperCase()
                byteArray[index] = hexValue.toInt(16).toByte()
                index++
            }
        }

        return byteArray
    }

Upvotes: 0

Related Questions