使用扫描线填充算法后,轮廓的边缘有一个间隙(未填充)

时间:2020-05-29 15:34:09

标签: android kotlin opengl-es brush

在Android平台上,用扫描线填充指定的区域(当前仅支持凸形)后,我发现轮廓的边缘有一些未填充的间隙。

它看起来像这样:

Fill renderings

它们主要集中在填充区域的右上角,并且在左上角有少量空白。实现代码如下:

class Fill02 : MainActivity.IFill {
    private val pixel = ByteBuffer.allocate(3)
    // Color to be filled
    private val color = ByteArray(3)
    private var xScanLeft = 0
    private var xScanRight = 0

    override fun fill(x: Int, y: Int, minX: Int, maxX: Int, minY: Int, maxY: Int, callback: MainActivity.IFillCallback) {
        val surfaceWidth = maxX - minX
        val surfaceHeight = maxY - minY

        GLES20.glReadPixels(x, y, 1, 1, GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, pixel)
        pixel.position(0)

        color[0] = pixel.get(0)
        color[1] = pixel.get(1)
        color[2] = pixel.get(2)

        var xLeft = x
        var xRight = x

        while (isSameColor(xLeft - 1, y) && 0 < xLeft) {
            xLeft--
        }

        while (isSameColor(xRight + 1, y) && xRight < surfaceWidth) {
            xRight++
        }

        callback.fullCallback(xLeft.toFloat(), surfaceHeight - y.toFloat())
        callback.fullCallback(xRight.toFloat(), surfaceHeight - y.toFloat())

        var yUp = y
        xScanLeft = xLeft
        xScanRight = xRight

        while (xScanLeft < xScanRight && yUp < maxY) {
            scanLine(++yUp, minX, maxX, surfaceHeight, callback)
        }

        var yDown = y
        xScanLeft = xLeft
        xScanRight = xRight

        while (xScanLeft < xScanRight && minY < yDown) {
            scanLine(--yDown, minX, maxX, surfaceHeight, callback)
        }
    }

    private fun scanLine(y: Int, minX: Int, maxX: Int, surfaceHeight: Int, callback: MainActivity.IFillCallback) {
        if (isSameColor(xScanLeft, y)) {
            while (minX < xScanLeft && isSameColor(xScanLeft - 1, y)) {
                xScanLeft--
            }
        } else {
            while (xScanLeft < xScanRight && !isSameColor(++xScanLeft, y)) {
            }
        }

        if (isSameColor(xScanRight, y)) {
            while (xScanRight < maxX && isSameColor(xScanRight + 1, y)) {
                xScanRight++
            }
        } else {
            while (xScanLeft < xScanRight && !isSameColor(--xScanRight, y)) {
            }
        }

        callback.fullCallback((xScanLeft).toFloat(), (surfaceHeight - y).toFloat())
        callback.fullCallback((xScanRight).toFloat(), (surfaceHeight - y).toFloat())
    }

    private fun isSameColor(x: Int, y: Int): Boolean {
        GLES20.glReadPixels(x, y, 1, 1, GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, pixel)
        pixel.position(0)
        return (color[0] == pixel.get(0) &&
                color[1] == pixel.get(1) &&
                color[2] == pixel.get(2))
    }
}

callback.fullCallback方法代码如下:

override fun fullCallback(x: Float, y: Float) {
    buffer.put((x - mSurfaceSize.x) / mSurfaceSize.x)
    buffer.put((mSurfaceSize.y - y) / mSurfaceSize.y)
}

override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
    mSurfaceSize.set(width / 2.0f, height / 2.0f)
    GLES20.glViewport(0, 0, width, height)
}

顶点着色器代码如下:

attribute vec2 vPosition;

uniform float vPointSize;

void main() {
    gl_PointSize = vPointSize;
    gl_Position = vec4(vPosition, 0.0, 1.0);
}

完整的源代码位于GitHub上。

请问是什么问题?

附件1:

修改代码后,图片已导出。

enter image description here

导出图片的代码如下:

private fun save() {
    isSave = false
    val w = mSurfaceSize.x.toInt() * 2
    val h = mSurfaceSize.y.toInt() * 2
    val screenshotSize = w * h
    val pixels = IntBuffer.allocate(screenshotSize)
    GLES20.glReadPixels(0, 0, w, h, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, pixels)
    GlobalScope.launch {
        val buffer = IntBuffer.allocate(screenshotSize)
        for (i in 0 until h) {
            for (j in 0 until w) {
                buffer.put((h - i - 1) * w + j, pixels.get(i * w + j));
            }
        }
        val config = Bitmap.Config.ARGB_8888
        val bitmap = Bitmap.createBitmap(w, h, config)
        bitmap.eraseColor(Color.argb(0, 255, 255, 255))
        bitmap.copyPixelsFromBuffer(buffer)
        val out = FileOutputStream(savePath)
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out)
    }
}

0 个答案:

没有答案