I need to drop shadow from an object of type image.Image which has got an alpha channel. The goal is not to have the rectangle shadowed, but the alpha.
What I wanted to do is:
take out the alpha channel
turn it into a black RGB image
expand to N pixels (N=the size of the blur)
apply a gaussian blur
apply it as a background
The last point is quite simple, thanks to the "image/draw" API (I have no problem to cut an image in circle, and apply the mask, for example).
Outputting the alpha channel seems simple, too (for each pixel, apply a 255*alpha multiplication on R, G, and B, or use a grayscale image, and finally invert the white color to black)
It's clearly the dilation and blurring that I have a problem with.
I have nothing against the fact that the image changes size for this operation (at worst I will reduce the original image before transformation)
The question is "how to dilate and blur the alpha channel" with Go on an image.Image?
OK, after a while, I finally made this.
I rebuild the alpha and devide it by 2 (this will be a paramters).
I'm using github.com/disintegration/imaging package to blur the alpha.
func DropShadow(img image.Image, size float64) image.Image {
bounds := img.Bounds()
sizeInt := int(math.Ceil(size)) * 4
final := imaging.New(bounds.Dx()+sizeInt, bounds.Dy()+sizeInt, color.Alpha{})
for x := 0; x < bounds.Dx(); x++ {
for y := 0; y < bounds.Dy(); y++ {
_, _, _, a := img.At(x, y).RGBA()
final.Set(x+sizeInt/2, y+sizeInt/2, color.RGBA{0x0, 0x0, 0x0, uint8(a / 2)})
}
}
final = imaging.Blur(final, size)
final = imaging.Overlay(final, img, image.Point{sizeInt / 2, sizeInt / 2}, 1)
return final
}
It's only a bit curious that I need to scale by 4 the image to not have the shadow sticking to the border. But it does the job...
Related
So I'm making some rgba images pixel by pixel following a certain pattern and saving them as png later on and noticed that when alpha channel es changed with certain colors it changes the whole pixel color when stored as png.
I made a test to show what is currently happening:
img := image.NewRGBA(image.Rect(0, 0, 250, 250))
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
f.Read(b)
img.SetRGBA(x, y, color.RGBA{
249,
214,
133,
255,
})
}
}
var buff bytes.Buffer
err := png.Encode(&buff, img)
if err != nil {
log.Println(err)
return
}
This will print an image of color #F9D685. But if I change alpha into 200 it will print another one with #6844BC and transparency instead of printing the original color with it's transparency.
Is there a way to solve this? I believe that it's because I'm missing something but can't really figure it out and didn't find anything similar to what's happening to me on google/here.
That one is simple:
go doc color.RGBA
package color // import "image/color"
type RGBA struct {
R, G, B, A uint8
}
RGBA represents a traditional 32-bit alpha-premultiplied color, having 8
bits for each of red, green, blue and alpha.
An alpha-premultiplied color component C has been scaled by alpha (A), so
has valid values 0 <= C <= A.
You might be looking for color.NRGBA.
(Always, really always, consult the documentation of the involved types and functions. Always.)
I've looked around but can't find anything useful for drawing circles in golang.
I'd like to draw a draw with 2 given (inner and outer) radius and color all pixels in between.
One possible method would be to iterate through each pixel and color it until the ring has been created. Although, that seems really inefficient.
Any help on this would be greatly appreciated! :)
Please read this related question: Draw a rectangle in Golang?
To sum it up: the standard Go library does not provide primitive drawing or painting capabilities.
So yes, either you have to use a 3rd party library to draw a circle (such as github.com/llgcode/draw2d), or you have to do it yourself. Don't worry, it's not hard at all.
Drawing a single circle
First pick a circle drawing algorithm which is simple and efficient. I recommend the Midpoint circle algorithm.
You will find the algorithm on the linked Wikipedia page. Note: you do not have to understand it if you want to use it.
But we do need to implement the algorithm in Go. Which is rather simple:
func drawCircle(img draw.Image, x0, y0, r int, c color.Color) {
x, y, dx, dy := r-1, 0, 1, 1
err := dx - (r * 2)
for x > y {
img.Set(x0+x, y0+y, c)
img.Set(x0+y, y0+x, c)
img.Set(x0-y, y0+x, c)
img.Set(x0-x, y0+y, c)
img.Set(x0-x, y0-y, c)
img.Set(x0-y, y0-x, c)
img.Set(x0+y, y0-x, c)
img.Set(x0+x, y0-y, c)
if err <= 0 {
y++
err += dy
dy += 2
}
if err > 0 {
x--
dx += 2
err += dx - (r * 2)
}
}
}
That's all it takes. Just pass a draw.Image you want to draw on, and the parameters of the circle you want to draw (center point, radius and the color).
Let's see it in action. Let's create an image, draw a circle on it, and save the image to a file. This is all it takes:
img := image.NewRGBA(image.Rect(0, 0, 100, 100))
drawCircle(img, 40, 40, 30, color.RGBA{255, 0, 0, 255})
buf := &bytes.Buffer{}
if err := png.Encode(buf, img); err != nil {
panic(err)
}
if err := ioutil.WriteFile("circle.png", buf.Bytes(), 0666); err != nil {
panic(err)
}
Note: you could also encode the image directly to an os.File and "skip" the in-memory buffer. This is just for demonstration, and to verify our implementation works.
Drawing a ring (filling space between 2 circles)
This one isn't that trivial if you want to implement it yourself, but using a 3rd party lib here could really come handy.
Although most of them don't contain ring-painting support, they do have circle drawing support, and you can set the width of the line used to draw the circle.
So, set the line width to the value that is the difference of the 2 radius of your circles. And draw a circle with a new radius that is the arithmetic center of the 2 original radius.
Here's the algorithm (this is not runnable code):
// Helper functions abstracting the library you choose:
func setColor(c color.Color) {}
func setLineWidth(width float64) {}
func drawCircle(r, x, y float64) {}
// fillRing draws a ring, where r1 and r2 are 2 concentric circles,
// the boundaries of the ring, (x, y) being the center point.
func fillRing(r1, r2, x, y float64, c color.color) {
// Set drawing color:
setColor(c)
// Set line width:
width := r2 - r1
if width < 0 {
width = -width
}
setLineWidth(width)
// And finally draw a circle which will be a ring:
r := (r2 + r1) / 2
drawCircle(r, x, y)
}
Go's image.Image interface has three methods: Bounds (clearly necessary for determining the size of an image), At (which returns the actual color at each pixel), and ColorModel. This last method returns a color.Model, which is capable of converting a color from any model into the representation that this image uses.
Why is ColorModel a part of this interface? How is it used by consumers of the image.Image type? If I have an image img, and I know nothing about its underlying representation, what good does img.ColorModel() do me? I can convert any color into the proper model, but I don't see what I can use this converted color for; the other two ways of interacting with an image, At and Bounds, do not take colors as arguments.
Am I missing something? Do any standard library functions call the ColorModel method of an image.Image, and what for?
I'm not sure if I understand your question entirely, but I do not think the purpose of ColorModel() is to change the color. It is only to get the color model.
The standard library uses it mostly when encoding images, like in the png package:
switch m.ColorModel() {
case color.GrayModel:
e.cb = cbG8
case color.Gray16Model:
e.cb = cbG16
case color.RGBAModel, color.NRGBAModel, color.AlphaModel:
if opaque(m) {
e.cb = cbTC8
} else {
e.cb = cbTCA8
}
default:
if opaque(m) {
e.cb = cbTC16
} else {
e.cb = cbTCA16
}
}
Another hint on it's intended use can be found in the jpeg/writer:
// TODO(wathiede): switch on m.ColorModel() instead of type.
To extend the accepted answer:
Although the color.Model is capable of converting a color to a different color type, as said in the docs:
Interface ColorModel describes the image's color model.
i.e. it's not the pixel's color model. It looks similar, but the latter implies that an image may contain pixel(s) with a different color model.
Note that an image represents a rectangular grid of homogeneous colors, i.e. all pixels have the same color model. Once you understand the color model of an image, it's better and more efficient to cast the image to a particular concrete image type, then work directly on that particular image. The following snippet illustrates the idea:
switch img.ColorModel() {
case color.RGBAModel:
// Try to cast to RGBA first
m, ok := img.(*image.RGBA)
if !ok {
//not an RGBA image, do generic/custom processing,
//e.g. using interface exposed by image.Image
return
}
//Direct pixel access for performance
for y := m.Rect.Min.Y; y < m.Rect.Max.Y; y++ {
yp := (y - m.Rect.Min.Y) * m.Stride
for x := m.Rect.Min.X; x < m.Rect.Max.X; x++ {
rgba := m.Pix[yp+(x-m.Rect.Min.X)*4:] //[]byte{r, g, b, a}
//get rgba component
r, g, b, a := rgba[0], rgba[1], rgba[2], rgba[3]
//set r channel to RED
rgba[0] = 255
//...
}
}
}
is more efficient compared to the following code
// Less efficient image processing
// a type-switch on the color returned by the `At` method
b := img.Bounds()
for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ {
col := img.At(x, y)
switch col := col.(type) {
case color.RGBA:
//do something with pixel
}
}
}
I am trying to draw over an image using a template, the template image is the following
I want to colorize the image red, green, blue and yellow colors with custom colors and achieve something like this:
In order to achieve this I currently use this image as a base
And then draw over the template using draw.Draw(outfitImage, outfitImage.Bounds(), generatorImage, image.ZP, draw.Over)
This however gives a very weird result (nothing near the expected result), this is how I replace pixels
func paintPixels(img *image.NRGBA, base color.Color, dst color.Color) {
br, bg, bb, ba := base.RGBA()
dr, dg, db, _ := dst.RGBA()
for x := 0; x < img.Bounds().Dx(); x++ {
for y := 0; y < img.Bounds().Dy(); y++ {
r, g, b, a := img.At(x, y).RGBA()
if br == r && bg == g && bb == b && ba == a {
img.Set(x, y, color.RGBA{uint8(dr), uint8(dg), uint8(db), 255})
}
}
}
}
The result can vary depending on the alpha value I use when colorizing the image template. So I cant think of a way to achieve the expected result, I guess I should use a mask with draw.DrawMask but I have no clue where to start or how to achieve the result I am looking for
You look like you're just replacing pixels with the colour if all components match. If you look at the compositing methods in bild/blend you should find one that suits you for combining images - you probably want Opacity or Multiply modes and could extract code from this file:
https://github.com/anthonynsimon/bild/blob/master/blend/blend.go
I need to load an image and search for colors and replace them. For example on an image I need to search for all red pixels and convert them to purple.
I am doing the following (img is a valid .png image):
func colorize(img image.Image) {
b := image.NewRGBA(img.Bounds())
draw.Draw(b, b.Bounds(), img, image.ZP, draw.Src)
for x := 0; x < b.Bounds().Dx(); x++ {
for y := 0; y < b.Bounds().Dy(); y++ {
log.Println(b.At(x, y).RGBA())
}
}
}
Thing is img.At().RGBA() doesn't seem to return the proper R, G, B, A codes? I am getting numbers bigger than 255 for example.
So how should I read all the image pixels while being able to know the x and y position of them?
img.At().RGBA() is Color.RGBA(). Quoting its doc:
// RGBA returns the alpha-premultiplied red, green, blue and alpha values
// for the color. Each value ranges within [0, 0xffff], but is represented
// by a uint32 so that multiplying by a blend factor up to 0xffff will not
// overflow.
//
// An alpha-premultiplied color component c has been scaled by alpha (a),
// so has valid values 0 <= c <= a.
Components returned by RGBA() are in range 0..0xffff, not 0..0xff, and they are also alpha-premultiplied.
Manual decoding
One way to get back the red, green, blue components in the 0..255 range is to shift right by 8 for example:
r, g, b, a := b.At(x, y).RGBA()
r, g, b, a = r>>8, g>>8, b>>8, a>>8
log.Println(r, g, b) // Now in range 0..255
Converting to color.RGBA
Another way is to convert the color to color.RGBA which is a struct, containing the components plain and simple:
type RGBA struct {
R, G, B, A uint8
}
Since you are using image.NewRGBA() which returns an image of type image.RGBA, the colors returned by the Image.At() method will be of dynamic type color.RGBA, so you can simply use a type assertion:
rgbacol := b.At(x, y).(color.RGBA)
log.Println(rgbacol.R, rgbacol.G, rgbacol.B, rgbacol.A)
In general (if image is not of type image.RGBA), Image.At() may or may not be of concrete type color.RGBA.
So in the general case you need to convert the color to a value of type color.RGBA. Conversions between color models are modeled by color.Model, and the image/color package has predefined converters. What you need is color.RGBAModel. color.RGBAModel.Convert() will return a color.Color value whose dynamic type is surely color.RGBA.
Example using color.RGBAModel:
var c color.Color
c = color.Gray{160}
rgbacol := color.RGBAModel.Convert(c).(color.RGBA)
fmt.Println(rgbacol.R, rgbacol.G, rgbacol.B, rgbacol.A)
Output (try it on the Go Playground):
160 160 160 255
So in your loop do:
rgbacol := color.RGBAModel.Convert(b.At(x, y).(color.RGBA)
// rgbacol is a struct of type color.RGBA, components are in range 0..255
Note:
Above solutions still give you back the alpha pre-multiplied components. If you want to undo the alpha pre-multiplication, you may use color.NRGBAModel converter (instead of color.RGBAModel).