Exemple #1
0
// HardLight multiplies or screens the colours, depending on the blend
// colour. The effect is similar to shining a harsh spotlight on the image.
func HardLight(a, b image.Image) image.Image {
	return BlendPixels(a, b, func(c, d color.Color) color.Color {
		i, j, k, l := utils.NormalisedRGBAf(c)
		m, n, o, p := utils.NormalisedRGBAf(d)

		f := func(i, j float64) float64 {
			if j > 128 {
				return 255 - ((255-2*(j-128))*(255-i))/256
			}
			return (2 * j * i) / 256
		}

		r := f(i, m)
		g := f(j, n)
		b := f(k, o)
		a := p + l*(1-p)

		return color.NRGBA{
			uint8(utils.Truncatef(r)),
			uint8(utils.Truncatef(g)),
			uint8(utils.Truncatef(b)),
			uint8(utils.Truncatef(a * 255)),
		}
	})
}
Exemple #2
0
// cb is backdrop colour, cs is source (blend layer) colour
func BlendPixel(cb, cs color.Color, f Blender) color.Color {
	// Uses methods described in "PDF Reference, Third Edition" from Adobe
	//  see: http://www.adobe.com/devnet/pdf/pdf_reference_archive.html

	// result colour
	cr := f(cb, cs)

	rb, gb, bb, ab := utils.RatioRGBA(cb)
	rs, gs, bs, as := utils.RatioRGBA(cs)
	rr, gr, br, _ := utils.RatioRGBA(cr)

	// Color compositing formula, expanded form. (Section 7.2.5)
	red := ((1 - as) * ab * rb) + ((1 - ab) * as * rs) + (ab * as * rr)
	green := ((1 - as) * ab * gb) + ((1 - ab) * as * gs) + (ab * as * gr)
	blue := ((1 - as) * ab * bb) + ((1 - ab) * as * bs) + (ab * as * br)

	// Union function. (Section 7.2.6)
	alpha := ab + as - (ab * as)

	return color.RGBA{
		uint8(utils.Truncatef(red * 255)),
		uint8(utils.Truncatef(green * 255)),
		uint8(utils.Truncatef(blue * 255)),
		uint8(utils.Truncatef(alpha * 255)),
	}
}
Exemple #3
0
func ratioNRGBA(r, g, b, a float64) color.Color {
	return color.NRGBA{
		uint8(utils.Truncatef(r * 255)),
		uint8(utils.Truncatef(g * 255)),
		uint8(utils.Truncatef(b * 255)),
		uint8(utils.Truncatef(a * 255)),
	}
}
Exemple #4
0
func AdjustC(value float64) utils.Composable {
	return func(c color.Color) color.Color {
		r, g, b, a := utils.RatioRGBA(c)

		r = utils.Truncatef(math.Pow(r, 1/value) * 255)
		g = utils.Truncatef(math.Pow(g, 1/value) * 255)
		b = utils.Truncatef(math.Pow(b, 1/value) * 255)

		return color.NRGBA{uint8(r), uint8(g), uint8(b), uint8(a * 255)}
	}
}
Exemple #5
0
func AdjustC(value float64) utils.Composable {
	return func(c color.Color) color.Color {
		r, g, b, a := utils.RatioRGBA(c)

		r = utils.Truncatef((((r - 0.5) * value) + 0.5) * 255)
		g = utils.Truncatef((((g - 0.5) * value) + 0.5) * 255)
		b = utils.Truncatef((((b - 0.5) * value) + 0.5) * 255)
		a = a * 255

		return color.NRGBA{uint8(r), uint8(g), uint8(b), uint8(a)}
	}
}
Exemple #6
0
// BUG: Conversion is broken _somewhere_, check against IM results.
func (col HSLA) RGBA() (red, green, blue, alpha uint32) {
	h := col.H
	s := col.S
	l := col.L
	a := col.A

	h = math.Mod(h, 360)

	c := (1.0 - math.Abs(2.0*l-1.0)) * s

	hdash := h / 60.0
	x := c * (1 - math.Abs(math.Mod(hdash, 2)-1))

	var r, g, b float64
	if h == 0 {
		r = 0
		g = 0
		b = 0
	} else if hdash < 1 {
		r = c
		g = x
		b = 0
	} else if hdash < 2 {
		r = x
		g = c
		b = 0
	} else if hdash < 3 {
		r = 0
		g = c
		b = x
	} else if hdash < 4 {
		r = 0
		g = x
		b = c
	} else if hdash < 5 {
		r = x
		g = 0
		b = c
	} else if hdash < 6 {
		r = c
		g = 0
		b = x
	}

	m := l - 0.5*c

	red = uint32(utils.Truncatef((r+m)*a*255)) << 8
	green = uint32(utils.Truncatef((g+m)*a*255)) << 8
	blue = uint32(utils.Truncatef((b+m)*a*255)) << 8
	alpha = uint32(a*255) << 8

	return
}
Exemple #7
0
func (col HSIA) RGBA() (red, green, blue, alpha uint32) {
	var r, g, b float64
	h := col.H
	s := col.S
	i := col.I
	a := col.A

	// normalise h
	h = math.Mod(h, 360)

	// need h in radians for trig. calculations
	hrad := h

	// need hrad to be in interval [0, 2/3*Pi)
	if h >= 240 {
		hrad -= 240
	} else if h >= 120 {
		hrad -= 120
	}

	// finally do the conversion to radians
	hrad *= math.Pi / 180

	x := i * (1 - s)
	y := i * (1 + (s*math.Cos(hrad))/math.Cos(math.Pi/3-hrad))
	z := 3*i - (x + y)

	if h < 120 {
		b = x
		r = y
		g = z
	} else if h < 240 {
		r = x
		g = y
		b = z
	} else {
		g = x
		b = y
		r = z
	}

	red = uint32(utils.Truncatef(r*a*255)) << 8
	green = uint32(utils.Truncatef(g*a*255)) << 8
	blue = uint32(utils.Truncatef(b*a*255)) << 8
	alpha = uint32(a*255) << 8

	return
}
Exemple #8
0
// Overlay multiplies or screens the colours, depending on the base colour.
func Overlay(a, b image.Image) image.Image {
	return BlendPixels(a, b, func(c, d color.Color) color.Color {
		i, j, k, l := utils.NormalisedRGBAf(c)
		m, n, o, p := utils.NormalisedRGBAf(d)

		r := (i / 255) * (i + ((2*m)/255)*(255-i))
		g := (j / 255) * (j + ((2*n)/255)*(255-j))
		b := (k / 255) * (k + ((2*o)/255)*(255-k))
		a := p + l*(1-p)

		return color.NRGBA{
			uint8(utils.Truncatef(r)),
			uint8(utils.Truncatef(g)),
			uint8(utils.Truncatef(b)),
			uint8(utils.Truncatef(a * 255)),
		}
	})
}
Exemple #9
0
// BlendPixels takes the base and blend images and applies the given Blender to
// each of their pixel pairs.
func BlendPixels(a, b image.Image, f Blender) image.Image {
	ba := a.Bounds()
	bb := b.Bounds()
	width := int(utils.Min(uint32(ba.Dx()), uint32(bb.Dx())))
	height := int(utils.Min(uint32(ba.Dy()), uint32(bb.Dy())))

	result := image.NewRGBA(image.Rect(0, 0, width, height))

	for y := 0; y < height; y++ {
		for x := 0; x < width; x++ {
			// Uses methods described in "PDF Reference, Third Edition" from Adobe
			//  see: http://www.adobe.com/devnet/pdf/pdf_reference_archive.html

			// backdrop colour
			cb := a.At(x, y)
			// source colour
			cs := b.At(x, y)
			// result colour
			cr := f(cb, cs)

			rb, gb, bb, ab := utils.RatioRGBA(cb)
			rs, gs, bs, as := utils.RatioRGBA(cs)
			rr, gr, br, _ := utils.RatioRGBA(cr)

			// Color compositing formula, expanded form. (Section 7.2.5)
			red := ((1 - as) * ab * rb) + ((1 - ab) * as * rs) + (ab * as * rr)
			green := ((1 - as) * ab * gb) + ((1 - ab) * as * gs) + (ab * as * gr)
			blue := ((1 - as) * ab * bb) + ((1 - ab) * as * bs) + (ab * as * br)

			// Union function. (Section 7.2.6)
			alpha := ab + as - (ab * as)

			result.Set(x, y, color.RGBA{
				uint8(utils.Truncatef(red * 255)),
				uint8(utils.Truncatef(green * 255)),
				uint8(utils.Truncatef(blue * 255)),
				uint8(utils.Truncatef(alpha * 255)),
			})
		}
	}

	return result
}
Exemple #10
0
// UnsharpMask sharpens the given Image using the unsharp mask technique.
// Basically the image is blurred, then subtracted from the original for
// differences above the threshold value.
func UnsharpMask(in image.Image, radius int, sigma, amount, threshold float64) image.Image {
	blurred := blur.Gaussian(in, radius, sigma, blur.IGNORE)
	bounds := in.Bounds()
	out := image.NewRGBA(bounds)

	// Absolute difference between a and b, returns float64 between 0 and 1.
	diff := func(a, b float64) float64 {
		if a > b {
			return a - b
		}
		return b - a
	}

	for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
		for x := bounds.Min.X; x < bounds.Max.X; x++ {
			ar, ag, ab, aa := utils.RatioRGBA(in.At(x, y))
			br, bg, bb, _ := utils.RatioRGBA(blurred.At(x, y))

			if diff(ar, br) >= threshold {
				ar = amount*(ar-br) + ar
			}

			if diff(ag, bg) >= threshold {
				ag = amount*(ag-bg) + ag
			}

			if diff(ab, bb) >= threshold {
				ab = amount*(ab-bb) + ab
			}

			out.Set(x, y, color.NRGBA{
				uint8(utils.Truncatef(ar * 255)),
				uint8(utils.Truncatef(ag * 255)),
				uint8(utils.Truncatef(ab * 255)),
				uint8(aa * 255),
			})
		}
	}

	return out
}
Exemple #11
0
func SigmoidalC(factor, midpoint float64) utils.Composable {
	alpha := midpoint
	beta := factor

	f := func(u float64) float64 {
		return (1.0/(1.0+math.Exp(beta*(alpha-u))) -
			1.0/(1.0+math.Exp(beta))) /
			(1.0/(1.0+math.Exp(beta*(alpha-1))) -
				1.0/(1.0+math.Exp(beta*alpha)))
	}

	return func(c color.Color) color.Color {
		r, g, b, a := utils.RatioRGBA(c)

		r = utils.Truncatef(f(r) * 255)
		g = utils.Truncatef(f(g) * 255)
		b = utils.Truncatef(f(b) * 255)
		a = a * 255

		return color.NRGBA{uint8(r), uint8(g), uint8(b), uint8(a)}
	}
}
Exemple #12
0
func setAlpha(c color.Color, v float64) color.Color {
	r, g, b, _ := utils.NormalisedRGBA(c)
	v = utils.Truncatef(255 * v)

	return color.NRGBA{uint8(r), uint8(g), uint8(b), uint8(v)}
}
Exemple #13
0
func setBlue(c color.Color, v float64) color.Color {
	r, g, _, a := utils.NormalisedRGBA(c)
	v = utils.Truncatef(255 * v)

	return color.NRGBA{uint8(r), uint8(g), uint8(v), uint8(a)}
}
Exemple #14
0
func setGreen(c color.Color, v float64) color.Color {
	r, _, b, a := utils.NormalisedRGBA(c)
	v = utils.Truncatef(255 * v)

	return color.NRGBA{uint8(r), uint8(v), uint8(b), uint8(a)}
}
Exemple #15
0
func setRed(c color.Color, v float64) color.Color {
	_, g, b, a := utils.NormalisedRGBA(c)
	v = utils.Truncatef(255 * v)

	return color.NRGBA{uint8(v), uint8(g), uint8(b), uint8(a)}
}
Exemple #16
0
func Convolve(in image.Image, weights Kernel, style Style) image.Image {
	bnds := in.Bounds()
	mid := weights.Mid()
	o := image.NewRGBA(bnds)

	for y := bnds.Min.Y; y < bnds.Max.Y; y++ {
		for x := bnds.Min.X; x < bnds.Max.X; x++ {
			var r, g, b, a, offset float64

			for oy := 0; oy < weights.Height(); oy++ {
				for ox := 0; ox < weights.Width(); ox++ {
					factor := weights[oy][ox]
					pt := image.Pt(x+ox-mid.X, y+oy-mid.Y)

					if pt == weights.Mid() {
						// Ignore!

					} else if pt.In(bnds) {
						or, og, ob, oa := in.At(pt.X, pt.Y).RGBA()

						r += float64(or) * factor
						g += float64(og) * factor
						b += float64(ob) * factor
						a += float64(oa) * factor

					} else {
						switch style {
						case CLAMP:
							offset += factor

						case WRAP:
							if pt.X >= bnds.Max.X {
								pt.X = pt.X - bnds.Max.X
							} else if pt.X < bnds.Min.X {
								pt.X = bnds.Dx() + pt.X
							}

							if pt.Y >= bnds.Max.Y {
								pt.Y = pt.Y - bnds.Max.Y
							} else if pt.Y < bnds.Min.Y {
								pt.Y = bnds.Dy() + pt.Y
							}

							or, og, ob, oa := in.At(pt.X, pt.Y).RGBA()

							r += float64(or) * factor
							g += float64(og) * factor
							b += float64(ob) * factor
							a += float64(oa) * factor
						}
					}
				}
			}

			if offset != 0 && style == CLAMP {
				or, og, ob, oa := in.At(x, y).RGBA()
				r += float64(or) * offset
				g += float64(og) * offset
				b += float64(ob) * offset
				a += float64(oa) * offset
			}

			o.Set(x, y, color.RGBA{
				uint8(utils.Truncatef(r / 255)),
				uint8(utils.Truncatef(g / 255)),
				uint8(utils.Truncatef(b / 255)),
				uint8(utils.Truncatef(a / 255)),
			})
		}
	}

	return o
}