После использования алгоритма заполнения строки сканирования на краю контура остается зазор (незаполненный) - PullRequest
1 голос
/ 29 мая 2020

На платформе 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)
    }
}
...