package main import ( "fmt" "image" _ "image/jpeg" "image/png" "math/rand" "os" "time" ) func main() { if len(os.Args) == 1 || len(os.Args) > 4 || os.Args[1] == "help" { fmt.Printf(`usage: %s Supported dither options are: noop; naive; randomnoise; bayer{0,1}; bayer{0,1}n Supported input image formats are jpg, png `, os.Args[0]) os.Exit(0) } filename := os.Args[1] ditherer := os.Args[2] outfile := os.Args[3] i, codex, err := loadImage(filename) if err != nil { fmt.Printf("error loading %s; %v\n", filename, err) os.Exit(255) } fmt.Printf("loaded %s using %s\n", filename, codex) t := time.Now() var new image.Image switch ditherer { case "noop": new = apply(i, noOp) case "naive": new = apply(i, naiveBW) case "randomnoise": rand.Seed(time.Now().UnixNano()) new = apply(i, randomNoise) case "bayer0": new = apply(i, bayerDithering(0, false)) case "bayer0n": new = apply(i, bayerDithering(0, true)) case "bayer1": new = apply(i, bayerDithering(1, false)) case "bayer1n": new = apply(i, bayerDithering(1, true)) case "simpleerror": new = apply(i, simpleErrorDiffusion()) case "floydsteinberg": new = apply(i, floydSteinberg()) default: fmt.Printf("unknown ditherer option: %s\n", ditherer) os.Exit(2) } fmt.Printf("dithering took %s\n", time.Since(t)) err = saveImage(outfile, new) if err != nil { fmt.Printf("error saving %s; %v\n", outfile, err) os.Exit(255) } fmt.Printf("saved output to %s\n", outfile) } func loadImage(filename string) (image.Image, string, error) { r, err := os.Open(filename) if err != nil { return nil, "", err } return image.Decode(r) } func saveImage(filename string, img image.Image) error { f, err := os.Create(filename) if err != nil { return err } if err := png.Encode(f, img); err != nil { f.Close() return err } if err := f.Close(); err != nil { return err } return nil }