utils_test.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. package imaging
  2. import (
  3. "image"
  4. "math"
  5. "runtime"
  6. "testing"
  7. )
  8. var (
  9. testdataBranchesJPG = mustOpen("testdata/branches.jpg")
  10. testdataBranchesPNG = mustOpen("testdata/branches.png")
  11. testdataFlowersSmallPNG = mustOpen("testdata/flowers_small.png")
  12. )
  13. func mustOpen(filename string) image.Image {
  14. img, err := Open(filename)
  15. if err != nil {
  16. panic(err)
  17. }
  18. return img
  19. }
  20. func TestParallel(t *testing.T) {
  21. for _, n := range []int{0, 1, 10, 100, 1000} {
  22. for _, p := range []int{1, 2, 4, 8, 16, 100} {
  23. if !testParallelN(n, p) {
  24. t.Fatalf("test [parallel %d %d] failed", n, p)
  25. }
  26. }
  27. }
  28. }
  29. func testParallelN(n, procs int) bool {
  30. data := make([]bool, n)
  31. before := runtime.GOMAXPROCS(0)
  32. runtime.GOMAXPROCS(procs)
  33. parallel(0, n, func(is <-chan int) {
  34. for i := range is {
  35. data[i] = true
  36. }
  37. })
  38. runtime.GOMAXPROCS(before)
  39. for i := 0; i < n; i++ {
  40. if !data[i] {
  41. return false
  42. }
  43. }
  44. return true
  45. }
  46. func TestClamp(t *testing.T) {
  47. testCases := []struct {
  48. f float64
  49. u uint8
  50. }{
  51. {0, 0},
  52. {255, 255},
  53. {128, 128},
  54. {0.49, 0},
  55. {0.50, 1},
  56. {254.9, 255},
  57. {254.0, 254},
  58. {256, 255},
  59. {2500, 255},
  60. {-10, 0},
  61. {127.6, 128},
  62. }
  63. for _, tc := range testCases {
  64. if clamp(tc.f) != tc.u {
  65. t.Fatalf("test [clamp %v %v] failed: %v", tc.f, tc.u, clamp(tc.f))
  66. }
  67. }
  68. }
  69. func TestReverse(t *testing.T) {
  70. testCases := []struct {
  71. pix []uint8
  72. want []uint8
  73. }{
  74. {
  75. pix: []uint8{},
  76. want: []uint8{},
  77. },
  78. {
  79. pix: []uint8{1, 2, 3, 4},
  80. want: []uint8{1, 2, 3, 4},
  81. },
  82. {
  83. pix: []uint8{1, 2, 3, 4, 5, 6, 7, 8},
  84. want: []uint8{5, 6, 7, 8, 1, 2, 3, 4},
  85. },
  86. {
  87. pix: []uint8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
  88. want: []uint8{9, 10, 11, 12, 5, 6, 7, 8, 1, 2, 3, 4},
  89. },
  90. }
  91. for _, tc := range testCases {
  92. t.Run("", func(t *testing.T) {
  93. reverse(tc.pix)
  94. if !compareBytes(tc.pix, tc.want, 0) {
  95. t.Fatalf("got pix %v want %v", tc.pix, tc.want)
  96. }
  97. })
  98. }
  99. }
  100. func compareNRGBA(img1, img2 *image.NRGBA, delta int) bool {
  101. if !img1.Rect.Eq(img2.Rect) {
  102. return false
  103. }
  104. return compareBytes(img1.Pix, img2.Pix, delta)
  105. }
  106. func compareBytes(a, b []uint8, delta int) bool {
  107. if len(a) != len(b) {
  108. return false
  109. }
  110. for i := 0; i < len(a); i++ {
  111. if absint(int(a[i])-int(b[i])) > delta {
  112. return false
  113. }
  114. }
  115. return true
  116. }
  117. // compareNRGBAGolden is a special version of compareNRGBA used in golden tests.
  118. // All the golden images are generated on amd64 architecture. Due to differences
  119. // in floating-point rounding on different architectures, we need to add some
  120. // level of tolerance when comparing images on architectures other than amd64.
  121. // See https://golang.org/ref/spec#Floating_point_operators for information on
  122. // fused multiply and add (FMA) instruction.
  123. func compareNRGBAGolden(img1, img2 *image.NRGBA) bool {
  124. delta := 0
  125. if runtime.GOARCH != "amd64" {
  126. delta = 1
  127. }
  128. return compareNRGBA(img1, img2, delta)
  129. }
  130. func compareFloat64(a, b, delta float64) bool {
  131. return math.Abs(a-b) <= delta
  132. }
  133. var rgbHSLTestCases = []struct {
  134. r, g, b uint8
  135. h, s, l float64
  136. }{
  137. {
  138. r: 255,
  139. g: 0,
  140. b: 0,
  141. h: 0.000,
  142. s: 1.000,
  143. l: 0.500,
  144. },
  145. {
  146. r: 191,
  147. g: 191,
  148. b: 0,
  149. h: 0.167,
  150. s: 1.000,
  151. l: 0.375,
  152. },
  153. {
  154. r: 0,
  155. g: 128,
  156. b: 0,
  157. h: 0.333,
  158. s: 1.000,
  159. l: 0.251,
  160. },
  161. {
  162. r: 128,
  163. g: 255,
  164. b: 255,
  165. h: 0.500,
  166. s: 1.000,
  167. l: 0.751,
  168. },
  169. {
  170. r: 128,
  171. g: 128,
  172. b: 255,
  173. h: 0.667,
  174. s: 1.000,
  175. l: 0.751,
  176. },
  177. {
  178. r: 191,
  179. g: 64,
  180. b: 191,
  181. h: 0.833,
  182. s: 0.498,
  183. l: 0.500,
  184. },
  185. {
  186. r: 160,
  187. g: 164,
  188. b: 36,
  189. h: 0.172,
  190. s: 0.640,
  191. l: 0.392,
  192. },
  193. {
  194. r: 65,
  195. g: 27,
  196. b: 234,
  197. h: 0.697,
  198. s: 0.831,
  199. l: 0.512,
  200. },
  201. {
  202. r: 30,
  203. g: 172,
  204. b: 65,
  205. h: 0.374,
  206. s: 0.703,
  207. l: 0.396,
  208. },
  209. {
  210. r: 240,
  211. g: 200,
  212. b: 14,
  213. h: 0.137,
  214. s: 0.890,
  215. l: 0.498,
  216. },
  217. {
  218. r: 180,
  219. g: 48,
  220. b: 229,
  221. h: 0.788,
  222. s: 0.777,
  223. l: 0.543,
  224. },
  225. {
  226. r: 237,
  227. g: 119,
  228. b: 81,
  229. h: 0.040,
  230. s: 0.813,
  231. l: 0.624,
  232. },
  233. {
  234. r: 254,
  235. g: 248,
  236. b: 136,
  237. h: 0.158,
  238. s: 0.983,
  239. l: 0.765,
  240. },
  241. {
  242. r: 25,
  243. g: 203,
  244. b: 151,
  245. h: 0.451,
  246. s: 0.781,
  247. l: 0.447,
  248. },
  249. {
  250. r: 54,
  251. g: 38,
  252. b: 152,
  253. h: 0.690,
  254. s: 0.600,
  255. l: 0.373,
  256. },
  257. {
  258. r: 126,
  259. g: 126,
  260. b: 184,
  261. h: 0.667,
  262. s: 0.290,
  263. l: 0.608,
  264. },
  265. }
  266. func TestRGBToHSL(t *testing.T) {
  267. for _, tc := range rgbHSLTestCases {
  268. t.Run("", func(t *testing.T) {
  269. h, s, l := rgbToHSL(tc.r, tc.g, tc.b)
  270. if !compareFloat64(h, tc.h, 0.001) || !compareFloat64(s, tc.s, 0.001) || !compareFloat64(l, tc.l, 0.001) {
  271. t.Fatalf("(%d, %d, %d): got (%.3f, %.3f, %.3f) want (%.3f, %.3f, %.3f)", tc.r, tc.g, tc.b, h, s, l, tc.h, tc.s, tc.l)
  272. }
  273. })
  274. }
  275. }
  276. func TestHSLToRGB(t *testing.T) {
  277. for _, tc := range rgbHSLTestCases {
  278. t.Run("", func(t *testing.T) {
  279. r, g, b := hslToRGB(tc.h, tc.s, tc.l)
  280. if r != tc.r || g != tc.g || b != tc.b {
  281. t.Fatalf("(%.3f, %.3f, %.3f): got (%d, %d, %d) want (%d, %d, %d)", tc.h, tc.s, tc.l, r, g, b, tc.r, tc.g, tc.b)
  282. }
  283. })
  284. }
  285. }