英文:
Convert RBGA image to RGB byte array in effcient way
问题
我有一个C库和一个函数,它期望一个指向字节数组的指针,该数组包含一个以RGB格式表示的24位位图。Alpha通道不重要,可以截断。我尝试了类似这样的代码:
func load(filePath string) *image.RGBA {
imgFile, err := os.Open(filePath)
if err != nil {
fmt.Printf("无法读取文件 %v\n", err)
}
defer imgFile.Close()
img, _, err := image.Decode(imgFile)
if err != nil {
fmt.Printf("无法解码文件 %v\n", err)
}
return img.(*image.RGBA)
}
img := load("myimg.png")
bounds := img.Bounds()
width, height := bounds.Max.X, bounds.Max.Y
// 转换为RGB?可能不需要...
newImg := image.NewNRGBA(image.Rect(0, 0, width, height))
draw.Draw(newImg, newImg.Bounds(), img, bounds.Min, draw.Src)
// 将图像指针传递给C函数。
C.PaintOnImage(unsafe.Pointer(&newImg.Pix[0]), C.int(newImg.Bounds().Dy()), C.int(newImg.Bounds().Dx())
然而,似乎NRGBA也是基于每像素4个字节的。我可以通过使用GoCV来解决这个问题,但对于这么简单的任务来说,这似乎有点过度。在Go中有没有一种简单高效的方法来做到这一点?
英文:
I have a C library and function that expects a pointer to byte array that contains a 24 bit bitmap in RGB format. Alpha channel is not important and can be truncated. I've tried something like this:
func load(filePath string) *image.RGBA {
imgFile, err := os.Open(filePath)
if err != nil {
fmt.Printf("Cannot read file %v\n", err)
}
defer imgFile.Close()
img, _, err := image.Decode(imgFile)
if err != nil {
fmt.Printf("Cannot decode file %v\n", err)
}
return img.(*image.RGBA)
}
img := load("myimg.png")
bounds := img.Bounds()
width, height := bounds.Max.X, bounds.Max.Y
// Convert to RGB? Probably not...
newImg := image.NewNRGBA(image.Rect(0, 0, width, height))
draw.Draw(newImg, newImg.Bounds(), img, bounds.Min, draw.Src)
// Pass image pointer to C function.
C.PaintOnImage(unsafe.Pointer(&newImg.Pix[0]), C.int(newImg.Bounds().Dy()), C.int(newImg.Bounds().Dx())
However, it seems that NRGBA is also built on 4 bytes per pixel. I could solve this probably by using GoCV but this seems like overkill for such simple task. Is there a way to do this in a simple and efficient manner in Go?
答案1
得分: 0
标准库中没有RGB图像类型,但你可以很容易地组装RGB数组:
bounds := img.Bounds()
rgb := make([]byte, bounds.Dx()*bounds.Dy()*3)
idx := 0
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
offs := img.PixOffset(x, y)
copy(rgb[idx:], img.Pix[offs:offs+3])
idx += 3
}
}
img.Pix
数据保存了4字节的RGBA值。上面的代码只是复制了所有像素的前3字节RGB值。
由于Pix
数组中的行是连续的,你可以通过每行只调用一次PixOffset
并且每个像素前进4字节来改进上面的代码。手动复制3字节可能比调用copy()
函数更快(如果对你很重要,可以进行基准测试):
bounds := img.Bounds()
rgb := make([]byte, bounds.Dx()*bounds.Dy()*3)
idx := 0
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
offs := img.PixOffset(bounds.Min.X, y)
for x := bounds.Min.X; x < bounds.Max.X; x++ {
rgb[idx+0] = img.Pix[offs+0]
rgb[idx+1] = img.Pix[offs+1]
rgb[idx+2] = img.Pix[offs+2]
idx += 3
offs += 4
}
}
英文:
There is no RGB image type in the standard library, but you can assemble your RGB array pretty easily:
bounds := img.Bounds()
rgb := make([]byte, bounds.Dx()*bounds.Dy()*3)
idx := 0
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
offs := img.PixOffset(x, y)
copy(rgb[idx:], img.Pix[offs:offs+3])
idx += 3
}
}
The img.Pix
data holds the 4-byte RGBA values. The code above just copies the leading 3-byte RGB values of all pixels.
Since lines are continuous in the Pix
array, you can improve the above code by only calling PixOffset
onces per line, and advance by 4 bytes for every pixel. Also manually copying 3 bytes may be faster than calling copy()
(benchmark if it matters to you):
bounds := img.Bounds()
rgb := make([]byte, bounds.Dx()*bounds.Dy()*3)
idx := 0
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
offs := img.PixOffset(bounds.Min.X, y)
for x := bounds.Min.X; x < bounds.Max.X; x++ {
rgb[idx+0] = img.Pix[offs+0]
rgb[idx+1] = img.Pix[offs+1]
rgb[idx+2] = img.Pix[offs+2]
idx += 3
offs += 4
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论