首页 > 解决方案 > 使用 Go WebAssembly 访问 ImageData.data

问题描述

我想在 Go 中编写一个照片过滤器以将其用作 WebAssembly 模块。

Go 有类型js.Value。我可以Get, Set,IndexCall可以了。但是如何ImageData.data快速使用 Go 中的像素数组呢?data.Index(index).Int()使用and之类的东西.SetIndex(..., ...)非常慢。我没有检查,如果这得到正确的结果。

第一次尝试非常慢(大约比 JS 或 Rust 慢 50 倍):

func Convolve(canvas js.Value, matrix []float64, factor float64) {
    side := int(math.Sqrt(float64(len(matrix))))
    halfSide := int(side / 2)
    context := canvas.Call("getContext", "2d")
    source := context.Call("getImageData", 0.0, 0.0, canvas.Get("width").Int(), canvas.Get("height").Int())
    sourceData := source.Get("data")
    imageWidth := source.Get("width").Int()
    imageHeight := source.Get("height").Int()
    output := context.Call("createImageData", imageWidth, imageHeight)
    outputData := output.Get("data")

    for y := 0; y < imageHeight; y++ {
        for x := 0; x < imageWidth; x++ {
            outputIndex := (y * imageWidth + x) * 4
            r := 0.0
            g := 0.0
            b := 0.0
            for cy := 0; cy < side; cy++ {
                for cx := 0; cx < side; cx++ {
                    scy := y + cy - halfSide
                    scx := x + cx - halfSide
                    if scy >= 0 && scy < imageHeight && scx >= 0 && scx < imageWidth {
                        sourceIndex := (scy * imageWidth + scx) * 4
                        modify := matrix[cy * side + cx]
                        r += sourceData.Index(sourceIndex).Float() * modify
                        g += sourceData.Index(sourceIndex + 1).Float() * modify
                        b += sourceData.Index(sourceIndex + 2).Float() * modify
                    }
                }
            }
            outputData.SetIndex(outputIndex, r * factor)
            outputData.SetIndex(outputIndex + 1, g * factor)
            outputData.SetIndex(outputIndex + 2, b * factor)
            outputData.SetIndex(outputIndex + 3, sourceData.Index(outputIndex + 3))
        }
    }

    context.Call("putImageData", output, 0, 0);
}

标签: imagegoslicewebassembly

解决方案


Go 1.13(尚未发布)添加了 2 个函数syscall/js,允许您复制整个数组,因此您不必恢复调用Index()SetIndex()每个像素的每个组件!

tip您可以在当前看到它们:

https://tip.golang.org/pkg/syscall/js/#CopyBytesToGo

https://tip.golang.org/pkg/syscall/js/#CopyBytesToJS

所以基本上你可以做的是首先将整个图像数据复制到一个 Go 字节切片中,然后在 Go 中使用它(进行过滤),一旦你完成,复制回改变的切片。它只需要 2 个js系统调用。


推荐阅读