コード例 #1
0
ファイル: gbprint.go プロジェクト: onedesert/GBPrinter
// Transforms gray input image color depth to the palette defined in p
// The algorithm simply assigns the nearest palette color to each pixel,
// without distributing error in any way, so expect color banding
func ditheringAverage(img *image.Gray, p *color.Palette) {
	size := img.Bounds()
	for y := size.Min.Y; y < size.Max.Y; y++ {
		for x := size.Min.X; x < size.Max.X; x++ {
			c1 := img.GrayAt(x, y)
			c2 := p.Convert(c1).(color.Gray)
			img.SetGray(x, y, c2)
		}
	}
}
コード例 #2
0
ファイル: gbprint.go プロジェクト: onedesert/GBPrinter
// Dithering algorithms
// Dithering is the process of reducing the colorspace of an image to a more
// restricted palette. Since the Game Boy Printer only has a 2bit colorspace
// available, it's important that some dithering algorithms are implemented to
// deal with the fact. Depending on the properties of the dithering algorithm
// detail may or may not be preserved as well. Using simple techniques like
// average dithering will yield results with lots of color banding, while employing
// error diffusion techniques such as Floyd Steinberg will produce smoother
// results (color banding is replaced by the introduction of noise)
// The wikipedia article (http://en.wikipedia.org/wiki/Dither) is quite interesting
// and talks about some dithering algorithms, some of which are implemented here.
// Floyd Steinberg is an error diffusion dithering algorithm that adds the error
// of each color conversion to the neighbours of each pixel. This way it's possible
// to achieve a finer graded dithering
func ditheringFloydSteinberg(img *image.Gray, p *color.Palette) {
	size := img.Bounds()
	for y := size.Min.Y; y < size.Max.Y; y++ {
		for x := size.Min.X; x < size.Max.X; x++ {
			c1 := img.GrayAt(x, y)
			c2 := p.Convert(c1).(color.Gray)
			delta := int(c1.Y) - int(c2.Y)
			switch {
			case x+1 < size.Max.X && y < size.Max.Y:
				img.SetGray(x+1, y, color.Gray{uint8(int(img.GrayAt(x+1, y).Y) + delta*7/16)})
				fallthrough
			case x < size.Max.X && y+1 < size.Max.Y:
				img.SetGray(x, y+1, color.Gray{uint8(int(img.GrayAt(x, y+1).Y) + delta*5/16)})
				fallthrough
			case x-1 >= size.Min.X && y+1 < size.Max.Y:
				img.SetGray(x-1, y+1, color.Gray{uint8(int(img.GrayAt(x-1, y+1).Y) + delta*3/16)})
				fallthrough
			case x+1 < size.Max.X && y+1 < size.Max.Y:
				img.SetGray(x+1, y+1, color.Gray{uint8(int(img.GrayAt(x+1, y+1).Y) + delta*1/16)})
			}
			img.Set(x, y, c2)
		}
	}
}