我正在尝试写一个短的,它将读取一个PNG文件,并交换一个通道与另一个(R,G,B)是可能的选择.
然而,我无法找到如何从image.At(x,y)返回的color.Color对象中提取整数.一旦我可以使用交换的通道构造新的RGBA颜色,使用image.Set(x,y,color)将其写回可能会更容易.
我现在在这里(你可以跳到最后一个循环):
package main
import (
"flag"
"fmt"
//"image"
"image/color"
"image/png"
"os"
)
type Choice struct {
value string
valid bool
}
func (c *Choice) validate() {
goodchoices := []string{"R", "G", "B"}
for _, v := range goodchoices {
if c.value == v {
c.valid = true
}
}
}
func main() {
var fname string
var c1 Choice
var c2 Choice
flag.StringVar(&c1.value, "c1", "", "The color channel to swap - R or G or B ")
flag.StringVar(&c2.value, "c2", "", "The color channel to swap with - R or G or B ")
flag.StringVar(&fname, "f", "", "A .png image (normal map)")
flag.Parse()
c1.validate()
c2.validate()
if c1.valid == true && c2.valid == true {
fmt.Println("We could proceed..")
fmt.Println("Swapping channels:", c1.value, "<->", c2.value, "In", fname) //for testing
} else {
fmt.Println("Invalid channel... Please use R, G or B.")
return
}
file, err := os.Open(fname)
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
pic, err := png.Decode(file)
if err != nil {
fmt.Fprintf(os.Stderr, "%s: %v\n", fname, err)
return
}
b := pic.Bounds()
for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ {
col := pic.At(x, y)
???? How do I swap the channels in col ????
}
}
}
Run Code Online (Sandbox Code Playgroud)
我是Go和编程的新手,所以请在你的答案中考虑一下.谢谢.
嗯,这比我想象的要难 - 我想知道是否有人能想出更好的主意!
问题是你不知道png.Decode返回的具体类型- 它可能返回任何图像类型.您只有一个image.Image没有Set方法的接口.
为了解决这个问题,首先要定义一个可以设置像素的所有图像类型都满足的接口
type ImageSet interface {
Set(x, y int, c color.Color)
}
Run Code Online (Sandbox Code Playgroud)
接下来看看是否pic实现了接口(如果不接受则会发生恐慌 - 使用picSet,如果困扰你,可以使用ok表单)
// Get an interface which can set pixels
picSet := pic.(ImageSet)
Run Code Online (Sandbox Code Playgroud)
现在你的循环看起来像这样 - 我只交换了红色和绿色,所以你可以看到这个想法.
for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ {
col := pic.At(x, y)
r, g, b, a := col.RGBA()
// Swap green and red
newCol := color.RGBA{uint8(g>>8), uint8(r>>8), uint8(b>>8), uint8(a>>8)}
picSet.Set(x, y, newCol)
}
}
Run Code Online (Sandbox Code Playgroud)
我怀疑的这一个高性能版本将不得不使用一种类型的开关,以确定哪些图像类型是,则具有用于每一个与uint8s 24个比特图像和uint16s 48位图像等的自定义码
如果你想要去,这是完整的工作示例.虽然它在游乐场不起作用 - 你必须下载它.
更新:刚刚注意到您的评论.如果你知道你有一个RGBA图像,那么你可以使用一个类型断言来获取底层图像,这使得事情变得更加容易.
// Get an image.RGBA if it is one
rgba, ok := pic.(*image.RGBA)
if !ok {
fmt.Println("That wasn't an RGBA!")
return
}
for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ {
// Note type assertion to get a color.RGBA
col := rgba.At(x, y).(color.RGBA)
// Swap green and red
col.G, col.R = col.R, col.G
rgba.Set(x, y, col)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2150 次 |
| 最近记录: |