// TestMedian tests the median quantizer on png files found in the source // directory. Output files are prefixed with _median_. Files begining with // _ are skipped when scanning for input files. Note nothing is tested // with a fresh source tree--drop a png or two in the source directory // before testing to give the test something to work on. Png files in the // parent directory are similarly used for testing. Put files there // to compare results of the different quantizers. func TestMedian(t *testing.T) { for _, p := range glob(t) { f, err := os.Open(p) if err != nil { t.Log(err) // skip files that can't be opened continue } img, err := png.Decode(f) f.Close() if err != nil { t.Log(err) // skip files that can't be decoded continue } pDir, pFile := filepath.Split(p) for _, n := range []int{16, 256} { // prefix _ on file name marks this as a result fq, err := os.Create(fmt.Sprintf("%s_median_%d_%s", pDir, n, pFile)) if err != nil { t.Fatal(err) // probably can't create any others } var q quant.Quantizer = median.Quantizer(n) if err = png.Encode(fq, q.Image(img)); err != nil { t.Fatal(err) // any problem is probably a problem for all } } } }
func main() { mode := flag.String("mode", "median", "'median' or 'mean' (default 'median')") size := flag.Int("size", 16, "Palette size (default 16)") flag.Parse() paths := flag.Args() if len(paths) == 0 { log.Fatal("No images specified") } var wg sync.WaitGroup wg.Add(len(paths)) for _, path := range paths { go func(path string) { defer wg.Done() var buff bytes.Buffer buff.WriteString(fmt.Sprintf("\n%s\n", path)) reader, err := os.Open(path) if err != nil { log.Fatal(err) } defer reader.Close() img, _, err := image.Decode(reader) if err != nil { log.Fatal(err) } var q quant.Quantizer if *mode == "median" { q = median.Quantizer(*size) } else { q = mean.Quantizer(*size) } pal := q.Palette(img) for _, c := range pal.ColorPalette() { r, g, b, _ := c.RGBA() buff.WriteString(fmt.Sprintf("#%02x%02x%02x\n", uint8(r>>8), uint8(g>>8), uint8(b>>8))) } fmt.Print(buff.String()) }(path) } wg.Wait() }
// TestDither tests Sierra24A on png files found in the source directory. // Output files are prefixed with _dither_256_. Files begining with _ // are skipped when scanning for input files. Thus nothing is tested // with a fresh source tree--drop a png or two in the source directory // before testing to give the test something to work on. func TestDither(t *testing.T) { _, file, _, ok := runtime.Caller(0) if !ok { t.Fatal("runtime.Caller fail") } srcDir, _ := filepath.Split(file) // ignore file names starting with _, those are result files. imgs, err := filepath.Glob(srcDir + "[^_]*.png") if err != nil { t.Fatal(err) } const n = 256 // exercise draw.Quantizer interface var q draw.Quantizer = median.Quantizer(n) // exercise draw.Drawer interface var d draw.Drawer = quant.Sierra24A{} for _, p := range imgs { f, err := os.Open(p) if err != nil { t.Error(err) // skip files that can't be opened continue } img, err := png.Decode(f) f.Close() if err != nil { t.Error(err) // skip files that can't be decoded continue } pDir, pFile := filepath.Split(p) // prefix _ on file name marks this as a result fq, err := os.Create(fmt.Sprintf("%s_dither_%d_%s", pDir, n, pFile)) if err != nil { t.Fatal(err) // probably can't create any others } b := img.Bounds() pi := image.NewPaletted(b, q.Quantize(make(color.Palette, 0, n), img)) d.Draw(pi, b, img, b.Min) if err = png.Encode(fq, pi); err != nil { t.Fatal(err) // any problem is probably a problem for all } } }
func BenchmarkPalette(b *testing.B) { var img image.Image for _, p := range glob(b) { f, err := os.Open(p) if err != nil { b.Log(err) // skip files that can't be opened continue } img, err = png.Decode(f) f.Close() if err != nil { b.Log(err) // skip files that can't be decoded continue } break } var q quant.Quantizer = median.Quantizer(256) b.ResetTimer() for i := 0; i < b.N; i++ { q.Palette(img) } }
func (w *Weather) CreateGifImage(dateArray []string) error { g := &gif.GIF{ Image: []*image.Paletted{}, Delay: []int{}, LoopCount: 0, } for _, date := range dateArray { srcMain, err := w.downloadImage(date, "main") if err != nil { return err } srcTokyo, err := w.downloadImage(date, "tokyo") if err != nil { return err } srcNagaoka, err := w.downloadImage(date, "nagaoka") if err != nil { return err } srcKyoto, err := w.downloadImage(date, "kyoto") if err != nil { return err } q := median.Quantizer(256) p := q.Quantize(make(color.Palette, 0, 256), srcMain) rMain := srcMain.Bounds() rTokyo := srcTokyo.Bounds() rNagaoka := srcNagaoka.Bounds() // 画像を合成 minX := rMain.Min.X maxX := rMain.Max.X + rTokyo.Max.X minY := rMain.Min.Y maxY := rMain.Max.Y paletSize := image.Rect(0, 0, maxX, maxY) dst := image.NewPaletted(paletSize, p) for x := minX; x < maxX; x++ { divideX := x - rMain.Max.X for y := minY; y < maxY; y++ { if x < rMain.Max.X && y < rMain.Max.Y { // whole map dst.Set(x, y, srcMain.At(x, y)) } else if x > rMain.Max.X { if y < rNagaoka.Max.Y { // nagaoka dst.Set(x, y, srcNagaoka.At(divideX, y)) } else if y > rNagaoka.Max.Y && y < rNagaoka.Max.Y+rTokyo.Max.Y { // tokyo divideY := y - rNagaoka.Max.Y dst.Set(x, y, srcTokyo.At(divideX, divideY)) } else if y > rNagaoka.Max.Y+rTokyo.Max.Y { // kyoto divideY := y - (rNagaoka.Max.Y + rTokyo.Max.Y) dst.Set(x, y, srcKyoto.At(divideX, divideY)) } } else if x == rMain.Max.X /* || (x == rMain.Max.X && y == rNagaoka.Max.Y)*/ { // 境界線塗りつぶし dst.Set(x, y, color.RGBA{uint8(0), uint8(0), uint8(0), uint8(0)}) } } } g.Image = append(g.Image, dst) g.Delay = append(g.Delay, 100) } out, err := os.Create(w.Filename + ".gif") if err != nil { return err } defer out.Close() err = gif.EncodeAll(out, g) if err != nil { return err } return nil }
func main() { flag.Parse() c, err := colorful.Hex(*bg) if err != nil { log.Fatal(err) } f, err := os.Open(flag.Arg(0)) if err != nil { log.Fatal(err) } src, _, err := image.Decode(f) if err != nil { log.Fatal(err) } f.Close() g := &gif.GIF{ Image: []*image.Paletted{}, Delay: []int{}, LoopCount: 0, } var base float64 = (math.Pi * 2) * 10 * (*speed) / 360 if *reverse { base *= -1 } limit := int(360 / 10 / (*speed)) q := median.Quantizer(256) p := q.Quantize(make(color.Palette, 0, 256), src) for i := 0; i < limit; i++ { dst := image.NewPaletted(src.Bounds(), p) draw.Draw(dst, src.Bounds(), &image.Uniform{c}, image.ZP, draw.Src) err = graphics.Rotate(dst, src, &graphics.RotateOptions{Angle: base * float64(i)}) if err != nil { log.Fatal(err) } if *zoom { w, h := float64(src.Bounds().Dx()), float64(src.Bounds().Dy()) tmp := image.NewPaletted(src.Bounds(), p) draw.Draw(tmp, src.Bounds(), &image.Uniform{c}, image.ZP, draw.Src) z := float64(0.5 + float64(i)/30.0) graphics.I. Scale(z, z). Translate((w-w*z)/2, (h-h*z)/2). Transform(tmp, dst, interp.Bilinear) dst = tmp } g.Image = append(g.Image, dst) g.Delay = append(g.Delay, *delay) } out, err := os.Create(*output) if err != nil { log.Fatal(err) } defer out.Close() err = gif.EncodeAll(out, g) if err != nil { log.Fatal(err) } }