简体   繁体   English

向图像调色板添加颜色

[英]Adding color to an image palette

I'm creating a utility in go that will load an image (a PNG or GIF) and overlay it with another image, to help debug this problem I am having I wrote a bit of code that will highlight the border of the transparency in red, so red color.Color{R:255,G:0,B:0,A:255} needs to be added to the palette if it is not in there already, all of this uses the same code as the image overlay process but is far simpler to understand so I will be sharing that code here.我在 go 中创建了一个实用程序,它将加载一个图像(PNG 或 GIF)并用另一个图像覆盖它,以帮助调试这个问题我写了一些代码,以红色突出显示透明度的边框,所以 red color.Color{R:255,G:0,B:0,A:255}需要添加到调色板中,如果它已经不在那里,所有这些都使用与图像叠加过程相同的代码但理解起来要简单得多,所以我将在这里分享该代码。

I have this working fine except for one aspect, and that is that I need the palette of the overlay to be added to the source image.除了一个方面,我的这个工作正常,那就是我需要将叠加层的调色板添加到源图像中。

I'm able to extract and append to the palette of the source image and create a new image.Paletted which contains all the image.Image.Pix data from the source image, and the image.Paletted.Palette contains the new colors, however when using image.Paletted.SetColorIndex() (after getting the proper index using image.Paletted.Palette.Index() and saving the result to a file, there are no changes.我能够提取image.Paletted源图像的调色板并创建一个新的image.Paletted ,其中包含来自源图像的所有image.Image.Pix数据,而image.Paletted.Palette包含新颜色当使用image.Paletted.SetColorIndex()使用得到适当的索引之后image.Paletted.Palette.Index()并将结果保存到一个文件中,没有任何更改。

Strangely, if I comment out all the palette code, the overlay image is written to the file, but the colors are adjusted to the closest neighbor in the source image (as per the go documentation).奇怪的是,如果我注释掉所有调色板代码,覆盖图像将写入文件,但颜色会调整为源图像中最近的邻居(根据 go 文档)。

I am unsure of why modifying the palette prevents me from writing to the image.我不确定为什么修改调色板会阻止我写入图像。

This is the code which loops through the edge pixels and draws red to them.这是循环遍历边缘像素并为它们绘制红色的代码。

func ApplyAttachment(img image.Image, augment *augment.Augment, attachment *augment.Attachment, debug bool) (appliedImage image.Image, err error) {
    edgePoints := FindEdge(img, EdgeFromString(attachment.Name))
    if debug {
        img, err = AddToPallete(img, red)
        if err != nil {
            logger.Warn("error adding to pallete: %s", err)
        }
        for _, pt := range edgePoints {
            if err = SetImagePixel(&img, pt.X, pt.Y, red); err != nil {
                logger.Warn("error setting image pixel: %s", err)
            }
        }
    } 
    ...

This is the code for AddToPalette这是 AddToPalette 的代码

// AddToPallete adds a color to the palette of an image.
func AddToPallete(addTo image.Image, c color.Color) (output image.Image, err error) {
    srcPallete := extractPallete(addTo)
    if !palleteContains(srcPallete, c) {
        srcPallete = append(srcPallete, c)
    }

    pImg := image.NewPaletted(addTo.Bounds(), srcPallete)
    ipImg := pImg.SubImage(pImg.Bounds())
    output, err = ImageOntoImage(&ipImg, &addTo, augment.Point{X: 0, Y: 0})
    return
}

This is the code for ImageOntoImage (which writes one image.Image onto another)这是 ImageOntoImage 的代码(将一个image.Image写入另一个)

// ImageOntoImage does exactly that
func ImageOntoImage(
    source *image.Image,
    overlay *image.Image,
    startAt augment.Point,
) (output image.Image, err error) {
    output = *source
    for curY := startAt.Y; curY < startAt.Y+(*overlay).Bounds().Max.Y; curY++ {
        for curX := startAt.X; curX < startAt.X+(*overlay).Bounds().Max.X; curX++ {
            c := output.At(curX, curY)
            oc := (*overlay).At(curX-startAt.X, curY-startAt.Y)
            cc := combineColors(c, oc)
            if err = SetImagePixel(&output, curX, curY, cc); err != nil {
                err = errors.New("Cannot modify image")
                return
            }
        }
    }
    return
}

// SetImagePixel sets a single pixel of an image to another color
func SetImagePixel(
    source *image.Image,
    x int,
    y int,
    color color.Color,
) (err error) {
    if poutput, ok := (*source).(*image.Paletted); ok {
        cindex := poutput.Palette.Index(color)
        poutput.SetColorIndex(x, y, uint8(cindex))
        asImg := image.Image(poutput)
        source = &asImg
    } else if coutput, ok := (*source).(Changeable); ok {
        coutput.Set(x, y, color)
    } else {
        err = errors.New("Cannot modify image")
        return
    }
    return
}


So to summarize, when I do not expand the palette, I am able to set pixels on an image, but the pixels are changed to the nearest color, when I do expand the palette, the pixels do not set, (or possibly, the nearest color is approximated to transparent somehow?)总而言之,当我不展开调色板时,我可以在图像上设置像素,但是像素会更改为最接近的颜色,当我展开调色板时,像素不会设置,(或者可能是最近的颜色以某种方式接近透明?)

So I feel a bit embarrassed.所以我觉得有点尴尬。 All my palette code was working fine.我所有的调色板代码都运行良好。 I was being burned by pointers.我被指针灼伤了。 By creating a new paletted image, I lost the connection to a pointer back to the original image, so setting the pixels was lost in the aether of go's scoping.通过创建一个新的调色板图像,我失去了与指向原始图像的指针的连接,因此在 go 的范围内设置像素丢失了。 This is why commenting out the palette code fixed it, the original pointer was still being used when the new pixels were set, when I created a paletted image, I out-scoped the original pointer and while it WAS setting the pixel correctly, the save image function was still referencing the original loaded image, so it was basically creating a copy of that image.这就是为什么注释掉调色板代码修复它的原因,当设置新像素时仍然使用原始指针,当我创建一个调色板图像时,我超出了原始指针的范围,而当它正确设置像素时,保存image 函数仍在引用原始加载的图像,因此它基本上是创建该图像的副本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM