| 19 | ) |
| 20 | |
| 21 | func drawHVLine(canvas draw.Image, x0, y0 int, dir byte, length int, dotted bool, startColor, endColor color.Color) { |
| 22 | if length < 1 { |
| 23 | return |
| 24 | } |
| 25 | |
| 26 | set := func(x, y int, clr color.Color) { |
| 27 | rgba := canvas.At(x, y).(color.RGBA) |
| 28 | n := clr.(color.RGBA) |
| 29 | r, g, b := int(n.R)*int(n.A)/255, int(n.G)*int(n.A)/255, int(n.B)*int(n.A)/255 |
| 30 | r0, g0, b0 := int(rgba.R)*int(255-n.A)/255, int(rgba.G)*int(255-n.A)/255, int(rgba.B)*int(255-n.A)/255 |
| 31 | c := func(a, b int) uint8 { |
| 32 | if a+b > 255 { |
| 33 | return 255 |
| 34 | } |
| 35 | return uint8(a + b) |
| 36 | } |
| 37 | |
| 38 | rgba.R, rgba.G, rgba.B = c(r, r0), c(g, g0), c(b, b0) |
| 39 | canvas.Set(x, y, rgba) |
| 40 | } |
| 41 | |
| 42 | if length == 1 { |
| 43 | set(x0, y0, startColor) |
| 44 | return |
| 45 | } |
| 46 | |
| 47 | sr, sg, sb, _ := startColor.RGBA() |
| 48 | er, eg, eb, _ := endColor.RGBA() |
| 49 | dr, dg, db := int(er)-int(sr), int(eg)-int(sg), int(eb)-int(sb) |
| 50 | clr, k := startColor.(color.RGBA), 0 |
| 51 | |
| 52 | ic := func(in uint32) uint8 { return uint8(in / 256) } |
| 53 | ici := func(in int) uint8 { return uint8(in / 256) } |
| 54 | |
| 55 | calcColor := func() { |
| 56 | if k == length-1 { |
| 57 | clr.R, clr.G, clr.B = ic(er), ic(eg), ic(eb) |
| 58 | } else { |
| 59 | k := k / 4 * 4 |
| 60 | clr.R, clr.G, clr.B = ici(int(sr)+dr*k/(length-1)), ici(int(sg)+dg*k/(length-1)), ici(int(sb)+db*k/(length-1)) |
| 61 | } |
| 62 | k++ |
| 63 | } |
| 64 | |
| 65 | switch dir { |
| 66 | case 's': |
| 67 | for y := y0; y < y0+length; y++ { |
| 68 | calcColor() |
| 69 | if !dotted || y%2 == 0 { |
| 70 | set(x0, y, clr) |
| 71 | } |
| 72 | } |
| 73 | case 'n': |
| 74 | for y := y0; y > y0-length; y-- { |
| 75 | calcColor() |
| 76 | if !dotted || y%2 == 0 { |
| 77 | set(x0, y, clr) |
| 78 | } |