Compare commits
3 Commits
b8b7ff7167
...
cbe14d53cd
Author | SHA1 | Date | |
---|---|---|---|
cbe14d53cd | |||
b9c6cf1a07 | |||
2bada11da1 |
6
main.go
6
main.go
@ -51,6 +51,12 @@ func main() {
|
|||||||
new = apply(i, bayerDithering(1, true))
|
new = apply(i, bayerDithering(1, true))
|
||||||
case "simpleerror":
|
case "simpleerror":
|
||||||
new = apply(i, simpleErrorDiffusion())
|
new = apply(i, simpleErrorDiffusion())
|
||||||
|
case "floydsteinberg":
|
||||||
|
new = apply(i, floydSteinberg())
|
||||||
|
case "jjn":
|
||||||
|
new = apply(i, jarvisJudiceNinke())
|
||||||
|
case "atkinson":
|
||||||
|
new = apply(i, atkinson())
|
||||||
default:
|
default:
|
||||||
fmt.Printf("unknown ditherer option: %s\n", ditherer)
|
fmt.Printf("unknown ditherer option: %s\n", ditherer)
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
|
88
quantizer.go
88
quantizer.go
@ -122,32 +122,98 @@ func bayerDithering(level int, invert bool) quantizerFunction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyError(diffusionMatrix map[coord]float64, divisor float64, quantError float64, currentPixel coord, errMap map[coord]float64) {
|
type diffusion struct {
|
||||||
for c, i := range diffusionMatrix {
|
matrix map[coord]float64
|
||||||
|
divisor float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyError(diffusion diffusion, quantError float64, currentPixel coord, errMap map[coord]float64) {
|
||||||
|
for c, i := range diffusion.matrix {
|
||||||
target := coord{x: currentPixel.x + c.x, y: currentPixel.y + c.y}
|
target := coord{x: currentPixel.x + c.x, y: currentPixel.y + c.y}
|
||||||
errMap[target] = errMap[target] + (quantError * (i / divisor))
|
errMap[target] = errMap[target] + (quantError * (i / diffusion.divisor))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func simpleErrorDiffusion() quantizerFunction {
|
func diffuser(errMap map[coord]float64, d diffusion) quantizerFunction {
|
||||||
errMap := make(map[coord]float64)
|
|
||||||
diffusionMatrix := map[coord]float64{
|
|
||||||
{x: 1, y: 0}: 1.0,
|
|
||||||
{x: 0, y: 1}: 1.0,
|
|
||||||
}
|
|
||||||
return func(x int, y int, c color.Color) color.Color {
|
return func(x int, y int, c color.Color) color.Color {
|
||||||
p := coord{x: x, y: y}
|
p := coord{x: x, y: y}
|
||||||
l := luminence(c) + errMap[p]
|
l := luminence(c) + errMap[p]
|
||||||
delete(errMap, p) // don't let the error map grow too big
|
delete(errMap, p) // don't let the error map grow too big
|
||||||
if l > 0.5 {
|
if l > 0.5 {
|
||||||
applyError(diffusionMatrix, 2.0, l-1.0, p, errMap)
|
applyError(d, l-1.0, p, errMap)
|
||||||
return color.White
|
return color.White
|
||||||
}
|
}
|
||||||
applyError(diffusionMatrix, 2.0, l, p, errMap)
|
applyError(d, l, p, errMap)
|
||||||
return color.Black
|
return color.Black
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func simpleErrorDiffusion() quantizerFunction {
|
||||||
|
errMap := make(map[coord]float64)
|
||||||
|
d := diffusion{
|
||||||
|
divisor: 2.0,
|
||||||
|
matrix: map[coord]float64{
|
||||||
|
{x: 1, y: 0}: 1.0,
|
||||||
|
{x: 0, y: 1}: 1.0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return diffuser(errMap, d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func floydSteinberg() quantizerFunction {
|
||||||
|
errMap := make(map[coord]float64)
|
||||||
|
d := diffusion{
|
||||||
|
divisor: 16.0,
|
||||||
|
matrix: map[coord]float64{
|
||||||
|
{x: 1, y: 0}: 7.0,
|
||||||
|
{x: -1, y: 1}: 3.0,
|
||||||
|
{x: 0, y: 1}: 5.0,
|
||||||
|
{x: 1, y: 1}: 1.0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return diffuser(errMap, d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func jarvisJudiceNinke() quantizerFunction {
|
||||||
|
errMap := make(map[coord]float64)
|
||||||
|
d := diffusion{
|
||||||
|
divisor: 48.0,
|
||||||
|
matrix: map[coord]float64{
|
||||||
|
{x: 1, y: 0}: 7.0,
|
||||||
|
{x: 2, y: 0}: 5.0,
|
||||||
|
|
||||||
|
{x: -2, y: 1}: 3.0,
|
||||||
|
{x: -1, y: 1}: 5.0,
|
||||||
|
{x: 0, y: 1}: 7.0,
|
||||||
|
{x: 1, y: 1}: 5.0,
|
||||||
|
{x: 2, y: 1}: 3.0,
|
||||||
|
|
||||||
|
{x: -2, y: 2}: 1.0,
|
||||||
|
{x: -1, y: 2}: 3.0,
|
||||||
|
{x: 0, y: 2}: 5.0,
|
||||||
|
{x: 1, y: 2}: 3.0,
|
||||||
|
{x: 2, y: 2}: 1.0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return diffuser(errMap, d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func atkinson() quantizerFunction {
|
||||||
|
errMap := make(map[coord]float64)
|
||||||
|
d := diffusion{
|
||||||
|
divisor: 8.0,
|
||||||
|
matrix: map[coord]float64{
|
||||||
|
{x: 1, y: 0}: 1.0,
|
||||||
|
{x: 2, y: 0}: 1.0,
|
||||||
|
{x: -1, y: 1}: 1.0,
|
||||||
|
{x: 0, y: 1}: 1.0,
|
||||||
|
{x: 1, y: 1}: 1.0,
|
||||||
|
{x: 0, y: 2}: 1.0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return diffuser(errMap, d)
|
||||||
|
}
|
||||||
|
|
||||||
// That is, "relative luminance": https://en.wikipedia.org/wiki/Relative_luminance.
|
// That is, "relative luminance": https://en.wikipedia.org/wiki/Relative_luminance.
|
||||||
// go's color library doesn't give any information on what "color space" the RGBA is derived from,
|
// go's color library doesn't give any information on what "color space" the RGBA is derived from,
|
||||||
// so we convert to Y'CbCr, which returns luminence directly as the Y component.
|
// so we convert to Y'CbCr, which returns luminence directly as the Y component.
|
||||||
|
Loading…
Reference in New Issue
Block a user