(pixels []color.NRGBA, width, height, transBits int)
| 27 | ) |
| 28 | |
| 29 | func applyPredictTransform(pixels []color.NRGBA, width, height, transBits int) (int, int, []color.NRGBA) { |
| 30 | bw := (width + (1 << transBits) - 1) >> transBits |
| 31 | bh := (height + (1 << transBits) - 1) >> transBits |
| 32 | |
| 33 | blocks := make([]color.NRGBA, bw * bh) |
| 34 | deltas := make([]color.NRGBA, width * height) |
| 35 | |
| 36 | accum := [][]int{ |
| 37 | make([]int, 256), |
| 38 | make([]int, 256), |
| 39 | make([]int, 256), |
| 40 | make([]int, 256), |
| 41 | make([]int, 40), |
| 42 | } |
| 43 | |
| 44 | histos := make([][]int, len(accum)) |
| 45 | for i := range accum { |
| 46 | histos[i] = make([]int, len(accum[i])) |
| 47 | } |
| 48 | |
| 49 | for y := 0; y < bh; y++ { |
| 50 | for x := 0; x < bw; x++ { |
| 51 | mx := min((x + 1) << transBits, width) |
| 52 | my := min((y + 1) << transBits, height) |
| 53 | |
| 54 | var best int |
| 55 | var bestEntropy float64 |
| 56 | for i := 0; i < 14; i++ { |
| 57 | for j := range accum { |
| 58 | copy(histos[j], accum[j]) |
| 59 | } |
| 60 | |
| 61 | for tx := x << transBits; tx < mx; tx++ { |
| 62 | for ty := y << transBits; ty < my; ty++ { |
| 63 | d := applyFilter(pixels, width, tx, ty, i) |
| 64 | |
| 65 | off := ty * width + tx |
| 66 | histos[0][int(uint8(pixels[off].R - d.R))]++ |
| 67 | histos[1][int(uint8(pixels[off].G - d.G))]++ |
| 68 | histos[2][int(uint8(pixels[off].B - d.B))]++ |
| 69 | histos[3][int(uint8(pixels[off].A - d.A))]++ |
| 70 | } |
| 71 | } |
| 72 | |
| 73 | var total float64 |
| 74 | for _, histo := range histos { |
| 75 | sum := 0 |
| 76 | sumSquares := 0 |
| 77 | |
| 78 | for _, count := range histo { |
| 79 | sum += count |
| 80 | sumSquares += count * count |
| 81 | } |
| 82 | |
| 83 | if sum == 0 { |
| 84 | continue |
| 85 | } |
| 86 |
searching dependent graphs…