简体   繁体   中英

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.

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.

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

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

// 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 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. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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