dongnue4923 2013-02-01 17:45
浏览 371
已采纳

Golang-使用Image和Image / PNG交换图片的PNG通道

I'm trying to write a short one, which will read a PNG file, and swap one channel with the other (R,G,B) being the possible choices.

I can't find out however, how to extract the integer from the color.Color object returned by image.At(x,y) . Writing it back would probably easier with image.Set(x,y,color) once i can construct the new RGBA color with the swapped channels.

Here I am now (you can pretty much skip to the last loop):

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
", 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 ???? 
    }
}
}

I'm really new to Go and programming in general, so please consider it in your answer. Thank You.

  • 写回答

1条回答 默认 最新

  • dongluxin2452 2013-02-01 19:58
    关注

    Hmmm, that was harder than I thought it would be - I wonder if anyone can come up with a better idea!

    The problem is that you don't know the concrete type that png.Decode returns - it may return any of the image types. You only have an image.Image interface which doesn't have a Set method.

    To get round that, first define an interface which all the Image types which can set pixels satisfies

    type ImageSet interface {
         Set(x, y int, c color.Color)
    }
    

    Next see whether pic implements that interface (go will panic if it doesn't - use the picSet, ok form if that bothers you)

    // Get an interface which can set pixels
    picSet := pic.(ImageSet)
    

    Now your loop looks like this - I only swapped red and green so you can see the idea.

    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)
        }
    }
    

    I suspect that a high performing version of this would have to use a type switch to determine which image type it was, then have a customized code for each one with uint8s for 24 bit images and uint16s for 48 bit images etc.

    Here is the complete working example if you want to have a go. It doesn't work in the playground though - you'll have to download it.


    Update: Just noticed your comment. If you know that you have an RGBA image, then you can use a type assertion to get the underlying image which makes things a whole lot easier.

    // 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)
        }
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器