// Dissolve randomly selects pixels from the blend image, depending on their // opacity. Blend pixels with higher opacities are more likely to be displayed. func Dissolve(a, b image.Image) 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++ { // base colour rb, gb, bb, ab := utils.RatioRGBA(a.At(x, y)) // blend colour rs, gs, bs, as := utils.RatioRGBA(b.At(x, y)) toPaint := ratioNRGBA(rb, gb, bb, ab) if rand.Float64() < as { toPaint = ratioNRGBA(rs, gs, bs, 1) } result.Set(x, y, toPaint) } } return result }
// Addition adds the blend colour to the base colour. (aka. Linear Dodge) func Addition(a, b image.Image) image.Image { return BlendPixels(a, b, func(c, d color.Color) color.Color { i, j, k, l := utils.NormalisedRGBA(c) m, n, o, p := utils.NormalisedRGBA(d) r := utils.Min(i+m, 255) g := utils.Min(j+n, 255) b := utils.Min(k+o, 255) a := utils.Min(l+p, 255) return color.NRGBA{uint8(r), uint8(g), uint8(b), uint8(a)} }) }
// 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 }
func MinimalC() utils.Composable { return colorAlterer(func(r, g, b uint32) uint32 { return utils.Min(r, g, b) }) }
func LightnessC() utils.Composable { return colorAlterer(func(r, g, b uint32) uint32 { return (utils.Max(r, g, b) + utils.Min(r, g, b)) / 2 }) }