Esempio n. 1
0
File: adjust.go Progetto: hawx/img
func LinearC(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)}
	}
}
Esempio n. 2
0
File: adjust.go Progetto: hawx/img
func SigmoidalC(factor, midpoint float64) utils.Composable {
	sigmoidal := func(x float64) float64 {
		return 1.0 / (1.0 + math.Exp(factor*(midpoint-x)))
	}

	// Pre-compute useful terms
	sig0 := sigmoidal(0.0)
	sig1 := sigmoidal(1.0)

	var scaledSigmoidal func(float64) float64

	if factor == 0 {
		scaledSigmoidal = func(x float64) float64 {
			return x
		}

	} else if factor > 0 {
		scaledSigmoidal = func(x float64) float64 {
			return (sigmoidal(x) - sig0) / (sig1 - sig0)
		}

	} else {
		scaledSigmoidal = func(x float64) float64 {
			argument := (sig1-sig0)*x + sig0
			var clamped float64
			if argument < Epsilon {
				clamped = Epsilon
			} else {
				if argument > 1-Epsilon {
					clamped = 1 - Epsilon
				} else {
					clamped = argument
				}
			}

			return midpoint - math.Log(1.0/clamped-1.0)/factor
		}
	}

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

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

		return color.NRGBA{uint8(r), uint8(g), uint8(b), uint8(a)}
	}
}
Esempio n. 3
0
File: hsla.go Progetto: hawx/img
// 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 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
}
Esempio n. 4
0
File: hsia.go Progetto: hawx/img
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
}
Esempio n. 5
0
File: sharpen.go Progetto: hawx/img
// 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
}
Esempio n. 6
0
File: vibrance.go Progetto: hawx/img
// AdjustC returns a Composable function that increases the saturation and
// decreases the lightness of unsaturated colours.
//
// Uses the same method as Darktable:
// https://github.com/darktable-org/darktable/blob/24c4a087fd020df587b5260f438bfaf494203cec/src/iop/vibrance.c
func AdjustC(amount float64) utils.Composable {
	return func(c color.Color) color.Color {
		r, g, b, a := utils.RatioRGBA(c)

		ll, la, lb := colorful.Color{r, g, b}.Lab()

		// saturation weight [0, 1]
		sw := math.Sqrt(la*la+lb*lb) / 2
		ls := 1.0 - amount*sw*0.25
		ss := 1.0 + amount*sw

		ll *= ls
		la *= ss
		lb *= ss

		f := colorful.Lab(ll, la, lb)

		fr := utils.Truncatef(f.R * 255)
		fg := utils.Truncatef(f.G * 255)
		fb := utils.Truncatef(f.B * 255)

		return color.NRGBA{uint8(fr), uint8(fg), uint8(fb), uint8(a * 255)}
	}
}
Esempio n. 7
0
File: blur.go Progetto: hawx/img
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
}
Esempio n. 8
0
File: channel.go Progetto: hawx/img
func (_ blueCh) Set(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)}
}
Esempio n. 9
0
File: channel.go Progetto: hawx/img
func (_ redCh) Set(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)}
}
Esempio n. 10
0
File: channel.go Progetto: hawx/img
func (_ alphaCh) Set(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)}
}