captcha.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. package main
  2. import (
  3. "image"
  4. "image/png"
  5. "os"
  6. "rand"
  7. "time"
  8. crand "crypto/rand"
  9. "io"
  10. )
  11. var numbers = [][]byte{
  12. {
  13. 0, 1, 1, 1, 0,
  14. 1, 0, 0, 0, 1,
  15. 1, 0, 0, 0, 1,
  16. 1, 0, 0, 0, 1,
  17. 1, 0, 0, 0, 1,
  18. 1, 0, 0, 0, 1,
  19. 1, 0, 0, 0, 1,
  20. 0, 1, 1, 1, 0,
  21. },
  22. {
  23. 0, 0, 1, 0, 0,
  24. 0, 1, 1, 0, 0,
  25. 1, 0, 1, 0, 0,
  26. 0, 0, 1, 0, 0,
  27. 0, 0, 1, 0, 0,
  28. 0, 0, 1, 0, 0,
  29. 0, 0, 1, 0, 0,
  30. 1, 1, 1, 1, 1,
  31. },
  32. {
  33. 0, 1, 1, 1, 0,
  34. 1, 0, 0, 0, 1,
  35. 0, 0, 0, 0, 1,
  36. 0, 0, 0, 1, 1,
  37. 0, 1, 1, 0, 0,
  38. 1, 0, 0, 0, 0,
  39. 1, 0, 0, 0, 0,
  40. 1, 1, 1, 1, 1,
  41. },
  42. {
  43. 1, 1, 1, 1, 1,
  44. 0, 0, 0, 0, 1,
  45. 0, 0, 0, 1, 1,
  46. 0, 1, 1, 0, 0,
  47. 0, 0, 0, 1, 0,
  48. 0, 0, 0, 0, 1,
  49. 0, 0, 0, 0, 1,
  50. 1, 1, 1, 1, 0,
  51. },
  52. {
  53. 1, 0, 0, 1, 0,
  54. 1, 0, 0, 1, 0,
  55. 1, 0, 0, 1, 0,
  56. 1, 0, 0, 1, 0,
  57. 1, 1, 1, 1, 1,
  58. 0, 0, 0, 1, 0,
  59. 0, 0, 0, 1, 0,
  60. 0, 0, 0, 1, 0,
  61. },
  62. {
  63. 1, 1, 1, 1, 1,
  64. 1, 0, 0, 0, 0,
  65. 1, 0, 0, 0, 0,
  66. 1, 1, 1, 1, 0,
  67. 0, 0, 0, 1, 1,
  68. 0, 0, 0, 0, 1,
  69. 0, 0, 0, 1, 1,
  70. 1, 1, 1, 1, 0,
  71. },
  72. {
  73. 0, 0, 1, 1, 1,
  74. 0, 1, 0, 0, 0,
  75. 1, 0, 0, 0, 0,
  76. 1, 1, 1, 1, 0,
  77. 1, 1, 0, 0, 1,
  78. 1, 0, 0, 0, 1,
  79. 1, 1, 0, 0, 1,
  80. 0, 1, 1, 1, 0,
  81. },
  82. {
  83. 1, 1, 1, 1, 1,
  84. 0, 0, 0, 0, 1,
  85. 0, 0, 0, 0, 1,
  86. 0, 0, 0, 1, 0,
  87. 0, 0, 1, 0, 0,
  88. 0, 1, 0, 0, 0,
  89. 0, 1, 0, 0, 0,
  90. 0, 1, 0, 0, 0,
  91. },
  92. {
  93. 0, 1, 1, 1, 0,
  94. 1, 0, 0, 0, 1,
  95. 1, 1, 0, 1, 1,
  96. 0, 1, 1, 1, 0,
  97. 1, 1, 0, 1, 1,
  98. 1, 0, 0, 0, 1,
  99. 1, 1, 0, 1, 1,
  100. 0, 1, 1, 1, 0,
  101. },
  102. {
  103. 0, 1, 1, 1, 0,
  104. 1, 0, 0, 1, 1,
  105. 1, 0, 0, 0, 1,
  106. 1, 1, 0, 0, 1,
  107. 0, 1, 1, 1, 1,
  108. 0, 0, 0, 0, 1,
  109. 0, 0, 0, 0, 1,
  110. 1, 1, 1, 1, 0,
  111. },
  112. }
  113. const (
  114. NumberWidth = 5
  115. NumberHeight = 8
  116. DotSize = 6
  117. SkewFactor = 3
  118. )
  119. func drawHorizLine(img *image.NRGBA, color image.Color, fromX, toX, y int) {
  120. for x := fromX; x <= toX; x++ {
  121. img.Set(x, y, color)
  122. }
  123. }
  124. func drawCircle(img *image.NRGBA, color image.Color, x0, y0, radius int) {
  125. f := 1 - radius
  126. ddF_x := 1
  127. ddF_y := -2 * radius
  128. x := 0
  129. y := radius
  130. img.Set(x0, y0+radius, color)
  131. img.Set(x0, y0-radius, color)
  132. //img.Set(x0+radius, y0, color)
  133. //img.Set(x0-radius, y0, color)
  134. drawHorizLine(img, color, x0-radius, x0+radius, y0)
  135. for x < y {
  136. // ddF_x == 2 * x + 1;
  137. // ddF_y == -2 * y;
  138. // f == x*x + y*y - radius*radius + 2*x - y + 1;
  139. if f >= 0 {
  140. y--
  141. ddF_y += 2
  142. f += ddF_y
  143. }
  144. x++
  145. ddF_x += 2
  146. f += ddF_x
  147. //img.Set(x0+x, y0+y, color)
  148. //img.Set(x0-x, y0+y, color)
  149. drawHorizLine(img, color, x0-x, x0+x, y0+y)
  150. //img.Set(x0+x, y0-y, color)
  151. //img.Set(x0-x, y0-y, color)
  152. drawHorizLine(img, color, x0-x, x0+x, y0-y)
  153. //img.Set(x0+y, y0+x, color)
  154. //img.Set(x0-y, y0+x, color)
  155. drawHorizLine(img, color, x0-y, x0+y, y0+x)
  156. //img.Set(x0+y, y0-x, color)
  157. //img.Set(x0-y, y0-x, color)
  158. drawHorizLine(img, color, x0-y, x0+y, y0-x)
  159. }
  160. }
  161. func min3(x, y, z uint8) (o uint8) {
  162. o = x
  163. if y < o {
  164. o = y
  165. }
  166. if z < o {
  167. o = z
  168. }
  169. return
  170. }
  171. func max3(x, y, z uint8) (o uint8) {
  172. o = x
  173. if y > o {
  174. o = y
  175. }
  176. if z > o {
  177. o = z
  178. }
  179. return
  180. }
  181. func setRandomBrightness(c *image.NRGBAColor, max uint8) {
  182. minc := min3(c.R, c.G, c.B)
  183. maxc := max3(c.R, c.G, c.B)
  184. if maxc > max {
  185. return
  186. }
  187. n := rand.Intn(int(max-maxc)) - int(minc)
  188. c.R = uint8(int(c.R) + n)
  189. c.G = uint8(int(c.G) + n)
  190. c.B = uint8(int(c.B) + n)
  191. }
  192. func fillWithCircles(img *image.NRGBA, n, maxradius int) {
  193. maxx := img.Bounds().Max.X
  194. maxy := img.Bounds().Max.Y
  195. color := image.NRGBAColor{0, 0, 0x80, 0xFF}
  196. for i := 0; i < n; i++ {
  197. setRandomBrightness(&color, 255)
  198. r := rand.Intn(maxradius-1)+1
  199. drawCircle(img, color, rand.Intn(maxx-r*2)+r, rand.Intn(maxy-r*2)+r, r)
  200. }
  201. }
  202. func drawNumber(img *image.NRGBA, number []byte, x, y int, color image.NRGBAColor) {
  203. skf := rand.Intn(SkewFactor)-SkewFactor/2
  204. if skf < 0 {
  205. x -= skf * NumberHeight
  206. }
  207. for y0 := 0; y0 < NumberHeight; y0++ {
  208. for x0 := 0; x0 < NumberWidth; x0++ {
  209. radius := rand.Intn(DotSize/2)+DotSize/2
  210. addx := rand.Intn(radius/2)
  211. addy := rand.Intn(radius/2)
  212. if number[y0*NumberWidth+x0] == 1 {
  213. drawCircle(img, color, x+x0*DotSize+DotSize+addx, y+y0*DotSize+DotSize+addy, radius)
  214. }
  215. }
  216. x += skf
  217. }
  218. }
  219. func drawNumbersToImage(ns []byte) {
  220. img := image.NewNRGBA(NumberWidth*(DotSize+2)*len(ns)+DotSize, NumberHeight*DotSize+(DotSize*6))
  221. for y := 0; y < img.Bounds().Max.Y; y++ {
  222. for x := 0; x < img.Bounds().Max.X; x++ {
  223. img.Set(x, y, image.NRGBAColor{0xFF, 0xFF, 0xFF, 0xFF})
  224. }
  225. }
  226. fillWithCircles(img, 60, 3)
  227. x := rand.Intn(DotSize)
  228. y := 0
  229. color := image.NRGBAColor{0, 0, 0x80, 0xFF}
  230. setRandomBrightness(&color, 180)
  231. for _, n := range ns {
  232. y = rand.Intn(DotSize*4)
  233. drawNumber(img, numbers[n], x, y, color)
  234. x += DotSize * NumberWidth + rand.Intn(SkewFactor)+3
  235. }
  236. f, err := os.Create("captcha.png")
  237. if err != nil {
  238. panic(err)
  239. }
  240. defer f.Close()
  241. png.Encode(f, img)
  242. }
  243. func main() {
  244. rand.Seed(time.Seconds())
  245. n := make([]byte, 6)
  246. if _, err := io.ReadFull(crand.Reader, n); err != nil {
  247. panic(err)
  248. }
  249. for i := range n {
  250. n[i] %= 10
  251. }
  252. drawNumbersToImage(n)
  253. }