Documentation ¶
Index ¶
- Variables
- func RoundClamp(i float32) uint16
- type Ditherer
- func (d *Ditherer) ClearMapper()
- func (d *Ditherer) Dither(src image.Image) image.Image
- func (d *Ditherer) DitherConfig(src draw.Image) (image.Image, image.Config)
- func (d *Ditherer) DitherCopy(src image.Image) *image.RGBA
- func (d *Ditherer) DitherCopyConfig(src image.Image) (*image.RGBA, image.Config)
- func (d *Ditherer) DitherPaletted(src image.Image) *image.Paletted
- func (d *Ditherer) DitherPalettedConfig(src image.Image) (*image.Paletted, image.Config)
- func (d *Ditherer) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point)
- func (d *Ditherer) GetColorModel() color.Model
- func (d *Ditherer) GetPalette() []color.Color
- func (d *Ditherer) Quantize(p color.Palette, m image.Image) color.Palette
- func (d *Ditherer) SetBayer(x, y uint, strength float32)
- func (d *Ditherer) SetOrdered(odm OrderedDitherMatrix, strength float32)
- func (d *Ditherer) SetRandomGrayscale(min, max float32)
- func (d *Ditherer) SetRandomRGB(minR, maxR, minG, maxG, minB, maxB float32)
- type ErrorDiffusionMatrix
- type OrderedDitherMatrix
- type SpecialDither
Constants ¶
This section is empty.
Variables ¶
var Atkinson = ErrorDiffusionMatrix{
{0, 0, 1.0 / 8, 1.0 / 8},
{1.0 / 8, 1.0 / 8, 1.0 / 8, 0},
{0, 1.0 / 8, 0, 0},
}
var Burkes = ErrorDiffusionMatrix{
{0, 0, 0, 8.0 / 32, 4.0 / 32},
{2.0 / 32, 4.0 / 32, 8.0 / 32, 4.0 / 32, 2.0 / 32},
}
var ClusteredDot4x4 = OrderedDitherMatrix{ Matrix: [][]uint{ {12, 5, 6, 13}, {4, 0, 1, 7}, {11, 3, 2, 8}, {15, 10, 9, 14}, }, Max: 16, }
ClusteredDot4x4 comes from http://caca.zoy.org/study/part2.html
It is not diagonal, so the dots form a grid.
var ClusteredDot6x6 = OrderedDitherMatrix{ Matrix: [][]uint{ {34, 29, 17, 21, 30, 35}, {28, 14, 9, 16, 20, 31}, {13, 8, 4, 5, 15, 19}, {12, 3, 0, 1, 10, 18}, {27, 7, 2, 6, 23, 24}, {33, 26, 11, 22, 25, 32}, }, Max: 36, }
ClusteredDot6x6 comes from Figure 5.9 of the book Digital Halftoning by Robert Ulichney. It can represent "37 levels of gray". It is not diagonal.
var ClusteredDot6x6_2 = OrderedDitherMatrix{ Matrix: [][]uint{ {34, 25, 21, 17, 29, 33}, {30, 13, 9, 5, 12, 24}, {18, 6, 1, 0, 8, 20}, {22, 10, 2, 3, 4, 16}, {26, 14, 7, 11, 15, 28}, {35, 31, 19, 23, 27, 32}, }, Max: 36, }
ClusteredDot6x6_2 comes from https://archive.is/71e9G. On the webpage it is called "central white point" while ClusteredDot6x6 is called "clustered dots".
It is nearly identical to ClusteredDot6x6.
var ClusteredDot6x6_3 = OrderedDitherMatrix{ Matrix: [][]uint{ {30, 22, 16, 21, 33, 35}, {24, 11, 7, 9, 26, 28}, {13, 5, 0, 2, 14, 19}, {15, 3, 1, 4, 12, 18}, {27, 8, 6, 10, 25, 29}, {32, 20, 17, 23, 31, 34}, }, Max: 36, }
ClusteredDot6x6_3 comes from https://archive.is/71e9G. On the webpage it is called "balanced centered point".
It is nearly identical to ClusteredDot6x6.
var ClusteredDot8x8 = OrderedDitherMatrix{ Matrix: [][]uint{ {3, 9, 17, 27, 25, 15, 7, 1}, {11, 29, 38, 46, 44, 36, 23, 5}, {19, 40, 52, 58, 56, 50, 34, 13}, {31, 48, 60, 63, 62, 54, 42, 21}, {30, 47, 59, 63, 61, 53, 41, 20}, {18, 39, 51, 57, 55, 49, 33, 12}, {10, 28, 37, 45, 43, 35, 22, 4}, {2, 8, 16, 26, 24, 14, 6, 0}, }, Max: 64, }
ClusteredDot8x8 comes from Figure 1.5 of the book Modern Digital Halftoning, Second Edition, by Daniel L. Lau and Gonzalo R. Arce. It is like ClusteredDotDiagonal8x8, but is not diagonal. It can represent "65 gray-levels".
var ClusteredDotDiagonal16x16 = OrderedDitherMatrix{ Matrix: [][]uint{ {63, 58, 50, 40, 41, 51, 59, 60, 64, 69, 77, 87, 86, 76, 68, 67}, {57, 33, 27, 18, 19, 28, 34, 52, 70, 94, 100, 109, 108, 99, 93, 75}, {49, 26, 13, 11, 12, 15, 29, 44, 78, 101, 114, 116, 115, 112, 98, 83}, {39, 17, 4, 3, 2, 9, 20, 42, 87, 110, 123, 124, 125, 118, 107, 85}, {38, 16, 5, 0, 1, 10, 21, 43, 89, 111, 122, 127, 126, 117, 106, 84}, {48, 25, 8, 6, 7, 14, 30, 45, 79, 102, 119, 121, 120, 113, 97, 82}, {56, 32, 24, 23, 22, 31, 35, 53, 71, 95, 103, 104, 105, 96, 92, 74}, {62, 55, 47, 37, 36, 46, 54, 61, 65, 72, 80, 90, 91, 81, 73, 66}, {64, 69, 77, 87, 86, 76, 68, 67, 63, 58, 50, 40, 41, 51, 59, 60}, {70, 94, 100, 109, 108, 99, 93, 75, 57, 33, 27, 18, 19, 28, 34, 52}, {78, 101, 114, 116, 115, 112, 98, 83, 49, 26, 13, 11, 12, 15, 29, 44}, {87, 110, 123, 124, 125, 118, 107, 85, 39, 17, 4, 3, 2, 9, 20, 42}, {89, 111, 122, 127, 126, 117, 106, 84, 38, 16, 5, 0, 1, 10, 21, 43}, {79, 102, 119, 121, 120, 113, 97, 82, 48, 25, 8, 6, 7, 14, 30, 45}, {71, 95, 103, 104, 105, 96, 92, 74, 56, 32, 24, 23, 22, 31, 35, 53}, {65, 72, 80, 90, 91, 81, 73, 66, 62, 55, 47, 37, 36, 46, 54, 61}, }, Max: 128, }
ClusteredDotDiagonal16x16 comes from Figure 5.4 of the book Digital Halftoning by Robert Ulichney. In the book it's called "M = 8". It can represent "129 levels of gray". Its dimensions are 16x16, but as a diagonal matrix it is 17x17. It is called "Diagonal" because the resulting dot pattern is at a 45 degree angle.
var ClusteredDotDiagonal6x6 = OrderedDitherMatrix{ Matrix: [][]uint{ {8, 6, 7, 9, 11, 10}, {5, 0, 1, 12, 17, 16}, {4, 3, 2, 13, 14, 15}, {9, 11, 10, 8, 6, 8}, {12, 17, 16, 5, 0, 1}, {13, 14, 15, 4, 3, 2}, }, Max: 18, }
ClusteredDotDiagonal6x6 comes from Figure 5.4 of the book Digital Halftoning by Robert Ulichney. In the book it's called "M = 3". It can represent "19 levels of gray". Its dimensions are 6x6, but as a diagonal matrix it is 7x7. It is called "Diagonal" because the resulting dot pattern is at a 45 degree angle.
var ClusteredDotDiagonal8x8 = OrderedDitherMatrix{ Matrix: [][]uint{ {24, 10, 12, 26, 35, 47, 49, 37}, {8, 0, 2, 14, 45, 59, 61, 51}, {22, 6, 4, 16, 43, 57, 63, 53}, {30, 20, 18, 28, 33, 41, 55, 39}, {34, 46, 48, 36, 25, 11, 13, 27}, {44, 58, 60, 50, 9, 1, 3, 15}, {42, 56, 62, 52, 23, 7, 5, 17}, {32, 40, 54, 38, 31, 21, 19, 29}, }, Max: 64, }
ClusteredDotDiagonal8x8 comes from http://caca.zoy.org/study/part2.html
They say it "mimics the halftoning techniques used by newspapers". It is called "Diagonal" because the resulting dot pattern is at a 45 degree angle.
var ClusteredDotDiagonal8x8_2 = OrderedDitherMatrix{ Matrix: [][]uint{ {13, 11, 12, 15, 18, 20, 19, 16}, {4, 3, 2, 9, 27, 28, 29, 22}, {5, 0, 1, 10, 26, 31, 30, 21}, {8, 6, 7, 14, 23, 25, 24, 17}, {18, 20, 19, 16, 13, 11, 12, 15}, {27, 28, 29, 22, 4, 3, 2, 9}, {26, 31, 30, 21, 5, 0, 1, 10}, {23, 25, 24, 17, 8, 6, 7, 14}, }, Max: 32, }
ClusteredDotDiagonal8x8_2 comes from Figure 5.4 of the book Digital Halftoning by Robert Ulichney. In the book it's called "M = 4". It can represent "33 levels of gray". Its dimensionsare 8x8, but as a diagonal matrix it is 9x9. It is called "Diagonal" because the resulting dot pattern is at a 45 degree angle.
It is almost identical to ClusteredDotDiagonal8x8, but worse because it can represent fewer gray levels. There is not much point in using it.
var ClusteredDotDiagonal8x8_3 = OrderedDitherMatrix{ Matrix: [][]uint{ {13, 9, 5, 12, 18, 22, 26, 19}, {6, 1, 0, 8, 25, 30, 31, 23}, {10, 2, 3, 4, 21, 29, 28, 27}, {14, 7, 11, 15, 17, 24, 20, 16}, {18, 22, 26, 19, 13, 9, 5, 12}, {25, 30, 31, 23, 6, 1, 0, 8}, {21, 29, 28, 27, 10, 2, 3, 4}, {17, 24, 20, 16, 14, 7, 11, 15}, }, Max: 32, }
ClusteredDotDiagonal8x8_3 comes from https://archive.is/71e9G. On the webpage it is called "diagonal ordered matrix with balanced centered points".
It is almost identical to ClusteredDotDiagonal8x8, but worse because it can represent fewer gray levels. There is not much point in using it.
It is called "Diagonal" because the resulting dot pattern is at a 45 degree angle.
var ClusteredDotHorizontalLine = OrderedDitherMatrix{ Matrix: [][]uint{ {35, 33, 31, 30, 32, 34}, {23, 21, 19, 18, 20, 22}, {11, 9, 7, 6, 8, 10}, {5, 3, 1, 0, 2, 4}, {17, 15, 13, 12, 14, 16}, {29, 27, 25, 24, 26, 28}, }, Max: 36, }
ClusteredDotHorizontalLine comes from Figure 5.13 of the book Digital Halftoning by Robert Ulichney. It can represent "37 levels of gray". Its dimensions are 6x6.
It "clusters pixels about horizontal lines".
var ClusteredDotSpiral5x5 = OrderedDitherMatrix{ Matrix: [][]uint{ {20, 21, 22, 23, 24}, {19, 6, 7, 8, 9}, {18, 5, 0, 1, 10}, {17, 4, 3, 2, 11}, {16, 15, 14, 13, 12}, }, Max: 25, }
ClusteredDotSpiral5x5 comes from Figure 5.13 of the book Digital Halftoning by Robert Ulichney. It can represent "26 levels of gray". Its dimensions are 5x5.
Instead of alternating dark and light dots like the other clustered-dot matrices, the dark parts grow to fill the area.
var ClusteredDotVerticalLine = OrderedDitherMatrix{ Matrix: [][]uint{ {35, 23, 11, 5, 17, 29}, {33, 21, 9, 3, 15, 27}, {31, 19, 7, 1, 13, 25}, {30, 18, 6, 0, 12, 24}, {32, 20, 8, 2, 14, 26}, {34, 22, 10, 4, 16, 28}, }, Max: 36, }
ClusteredDotVerticalLine is my rotated version of ClusteredDotHorizontalLine.
var FalseFloydSteinberg = ErrorDiffusionMatrix{
{0, 3.0 / 8},
{3.0 / 8, 2.0 / 8},
}
var FloydSteinberg = ErrorDiffusionMatrix{
{0, 0, 7.0 / 16},
{3.0 / 16, 5.0 / 16, 1.0 / 16},
}
var Horizontal3x5 = OrderedDitherMatrix{ Matrix: [][]uint{ {9, 10, 11}, {3, 4, 5}, {0, 1, 2}, {6, 7, 8}, {12, 13, 14}, }, Max: 15, }
Horizontal3x5 is my rotated version of Vertical5x3.
var JarvisJudiceNinke = ErrorDiffusionMatrix{
{0, 0, 0, 7.0 / 48, 5.0 / 48},
{3.0 / 48, 5.0 / 48, 7.0 / 48, 5.0 / 48, 3.0 / 48},
{1.0 / 48, 3.0 / 48, 5.0 / 48, 3.0 / 48, 1.0 / 48},
}
var Sierra = ErrorDiffusionMatrix{
{0, 0, 0, 5.0 / 32, 3.0 / 32},
{2.0 / 32, 4.0 / 32, 5.0 / 32, 4.0 / 32, 2.0 / 32},
{0, 2.0 / 32, 3.0 / 32, 2.0 / 32, 0},
}
var Sierra2 = TwoRowSierra
Sierra2 is another name for TwoRowSierra
var Sierra2_4A = SierraLite
Sierra2_4A (usually written as Sierra2-4A) is another name for SierraLite.
var Sierra3 = Sierra
Sierra3 is another name for the original Sierra matrix.
var SierraLite = ErrorDiffusionMatrix{
{0, 0, 2.0 / 4},
{1.0 / 4, 1.0 / 4, 0},
}
var Simple2D = ErrorDiffusionMatrix{
{0, 0.5},
{0.5, 0},
}
var StevenPigeon = ErrorDiffusionMatrix{
{0, 0, 0, 2.0 / 14, 1.0 / 14},
{0, 2.0 / 14, 2.0 / 14, 2.0 / 14, 0},
{1.0 / 14, 0, 1.0 / 14, 0, 1.0 / 14},
}
StevenPigeon is an error diffusion matrix developed by Steven Pigeon. Source: https://hbfs.wordpress.com/2013/12/31/dithering/
var Stucki = ErrorDiffusionMatrix{
{0, 0, 0, 8.0 / 42, 4.0 / 42},
{2.0 / 42, 4.0 / 42, 8.0 / 42, 4.0 / 42, 2.0 / 42},
{1.0 / 42, 2.0 / 42, 4.0 / 42, 2.0 / 42, 1.0 / 42},
}
var TwoRowSierra = ErrorDiffusionMatrix{
{0, 0, 0, 4.0 / 16, 3.0 / 16},
{1.0 / 16, 2.0 / 16, 3.0 / 16, 2.0 / 16, 1.0 / 16},
}
var Vertical5x3 = OrderedDitherMatrix{ Matrix: [][]uint{ {9, 3, 0, 6, 12}, {10, 4, 1, 7, 13}, {11, 5, 2, 8, 14}, }, Max: 15, }
Vertical5x3 comes from http://caca.zoy.org/study/part2.html
They say it "creates artistic vertical line artifacts".
Functions ¶
func RoundClamp ¶
RoundClamp clamps the number and rounds it, rounding ties to the nearest even number. This should be used if you're writing your own PixelMapper.
Types ¶
type Ditherer ¶
type Ditherer struct { // Matrix is the ErrorDiffusionMatrix for dithering. Matrix ErrorDiffusionMatrix // Special is the special dithering algorithm that's being used. The default // value of 0 indicates that no special dithering algorithm is being used. Special SpecialDither // SingleThreaded controls whether the dithering happens sequentially or using // runtime.GOMAXPROCS(0) workers, which defaults to the number of CPUs. // // Note that error diffusion dithering (using Matrix) is sequential by nature // and so this field has no effect. // // Setting this to true is only useful in rare cases, like when numbers are // used sequentially in a PixelMapper, and the output must be deterministic. // Because otherwise the numbers will be retrieved in a different order each // time, as the goroutines call on the PixelMapper. SingleThreaded bool // Serpentine controls whether the error diffusion matrix is applied in a // serpentine manner, meaning that it goes right-to-left every other line. // This greatly reduces line-type artifacts. If a Mapper is being used this // field will have no effect. Serpentine bool // contains filtered or unexported fields }
Ditherer dithers images according to the settings in the struct. It can be safely reused for many images, and used concurrently.
Some members of the struct are public. Those members can be changed in-between dithering images, if you would like to dither again. If you change those public methods while an image is being dithered, the output image will have problems, so only change in-between dithering.
You can only set one of Matrix, Mapper, or Special. Trying to dither when none or more than one of those are set will cause the function to panic.
All methods can handle images with transparency, unless otherwise specified. Read the docs before using!
func NewDitherer ¶
NewDitherer creates a new Ditherer that uses a copy of the provided palette. If the palette is empty or nil then nil will be returned. All palette colors should be opaque.
func (*Ditherer) ClearMapper ¶
func (d *Ditherer) ClearMapper()
ClearMapper clears out Mapper field of Ditherer struct. Useful if you want to reuse Ditherer object for the next dithering.
func (*Ditherer) Dither ¶
Dither dithers the provided image.
It will always try to change the provided image and return it, but if that is not possible it will return the dithered image as a copy.
In comparison to DitherCopy, this can greatly reduce memory usage, and is quicker because it usually won't copy the image at the beginning. It should be preferred if you don't need to keep the original image.
Cases where a copy will be are limited to: If the input image is *image.Paletted and the image's palette is different than the Ditherer's, or if the image can't be casted to draw.Image.
The returned image type when copied is *image.RGBA. But it may be different if the image wasn't copied.
func (*Ditherer) DitherConfig ¶
DitherConfig is like Dither, but returns an image.Config as well.
func (*Ditherer) DitherCopy ¶
DitherCopy dithers a copy of the src image and returns it. The src image remains unchanged. If you don't need to keep the original image, use Dither.
func (*Ditherer) DitherCopyConfig ¶
DitherCopyConfig is like DitherCopy, but returns an image.Config as well.
func (*Ditherer) DitherPaletted ¶
DitherPaletted dithers a copy of the src image and returns it as an *image.Paletted. The src image remains unchanged. If you don't need an *image.Paletted, using Dither or DitherCopy should be preferred.
The palette of the returned image is the same palette the ditherer uses internally -- it will be equal to the output of GetPalette().
If the Ditherer's palette has over 256 colors then the function will panic, because *image.Paletted does not allow for that.
DitherPaletted can't handle images with transparency.
func (*Ditherer) DitherPalettedConfig ¶
DitherPalettedConfig is like DitherPaletted, but returns an image.Config as well.
DitherPalettedConfig can't handle images with transparency.
func (*Ditherer) Draw ¶
Draw implements draw.Drawer. This means you can use a Ditherer in many places, such as for encoding GIFs.
Draw ignores whether dst has a palette or not, and just uses the internal Ditherer palette. If the dst image passed has a palette (i.e. is of the type *image.Paletted), and the palette is the not the same as the Ditherer's palette, it will panic.
func (*Ditherer) GetColorModel ¶
GetColorModel returns a copy of the Ditherer's palette as a color.Model that finds the closest color using Euclidean distance in sRGB space.
func (*Ditherer) GetPalette ¶
GetPalette returns a copy of the current palette being used by the Ditherer.
func (*Ditherer) Quantize ¶
Quantize implements draw.Quantizer. It ignores the provided image and just returns the Ditherer's palette each time. This is useful for places that only allow you to set the palette through a draw.Quantizer, like the image/gif package.
This function will panic if the Ditherer's palette has more colors than the caller wants, which the caller indicates by cap(p).
It will also panic if there's already colors in the color.Palette provided to the func and not all of those colors are included in the Ditherer's palette. This is because the caller is indicating that certain colors must be in the palette, but the user who created the Ditherer does not want those colors.
func (*Ditherer) SetBayer ¶
Sets Bayer PixelMapper to Ditherer stuct.
The provided dimensions of the bayer matrix [x,y] can only be powers of 2, but they do not need to be the same. If they are not powers of two, this function will panic.
Refer to documentation for `Bayer` function to get more information: https://pkg.go.dev/github.com/makeworld-the-better-one/dither/v2#Bayer
func (*Ditherer) SetOrdered ¶
func (d *Ditherer) SetOrdered(odm OrderedDitherMatrix, strength float32)
SetOrdered sets a dither matrix as a PixelMapper to Ditherer stuct. Refer to documentation for `PixelMapperFromMatrix` function to get more information: https://pkg.go.dev/github.com/makeworld-the-better-one/dither/v2#PixelMapperFromMatrix
func (*Ditherer) SetRandomGrayscale ¶
SetRandomGrayscale generates a grayscale random noise dithering and sets it to Ditherer stuct. Refer to documentation for `RandomNoiseGrayscale` function to get more information: https://pkg.go.dev/github.com/makeworld-the-better-one/dither/v2#RandomNoiseGrayscale
func (*Ditherer) SetRandomRGB ¶
SetRandomRGB generates a random noise dithering in RGB format and sets it to Ditherer stuct. Refer to documentation for `RandomNoiseRGB` function to get more information: https://pkg.go.dev/github.com/makeworld-the-better-one/dither/v2#RandomNoiseRGB
type ErrorDiffusionMatrix ¶
type ErrorDiffusionMatrix [][]float32
ErrorDiffusionMatrix holds the matrix for the error-diffusion type of dithering. An example of this would be Floyd-Steinberg or Atkinson.
Zero values can be used to represent pixels that have already been processed. The current pixel is assumed to be the right-most zero value in the top row.
func ErrorDiffusionStrength ¶
func ErrorDiffusionStrength(edm ErrorDiffusionMatrix, strength float32) ErrorDiffusionMatrix
ErrorDiffusionStrength modifies an existing error diffusion matrix so that it will be applied with the specified strength.
strength is usually a value from 0 to 1.0, where 1.0 means 100% strength, and will not modify the matrix at all. It is inversely proportional to contrast - reducing the strength increases the contrast. It can be useful at values like 0.8 for reducing noise in the dithered image.
See the documentation for Bayer for more details.
func (ErrorDiffusionMatrix) CurrentPixel ¶
func (e ErrorDiffusionMatrix) CurrentPixel() int
CurrentPixel returns the index the current pixel. The current pixel is assumed to be the right-most zero value in the top row. In all matrixes that I have seen, the current pixel is always in the middle, but this function exists just in case.
Therefore with an ErrorDiffusionMatrix named edm, the current pixel is at:
edm[0][edm.CurrentPixel()]
Usually you'll want to cache this value.
func (ErrorDiffusionMatrix) Offset ¶
func (e ErrorDiffusionMatrix) Offset(x, y, curPx int) (int, int)
Offset will take the index of where you are in the matrix and return the offset from the current pixel. You have to pass the curPx value yourself to allow for caching, but it can be retrieved by calling CurrentPixel().
type OrderedDitherMatrix ¶
OrderedDitherMatrix is used to hold a matrix used for ordered dithering. This is useful if you find a matrix somewhere and would like to try it out. You can create this struct and then give it to PixelMapperFromMatrix.
The matrix must be rectangular - each slice inside the first one must be the same length.
Max is the value all the matrix values will be divided by. Usually this is the product of the dimensions of the matrix (x*y), or the greatest value in the matrix plus one. For diagonal matrices or other matrices with repeated values, it is the latter.
Leaving Max as 0 will cause a panic.
Matrix values should almost always range from 0 to Max-1. If the matrix you found ranges from 1 to Max, just subtract 1 from every value when programming it.
type SpecialDither ¶
type SpecialDither int
SpecialDither is used to represent dithering algorithms that require custom code, because they cannot be represented by a PixelMapper or error diffusion matrix.
There are currently no SpecialDither options, but they will be added in the future.