nearest.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. package resize
  2. import "image"
  3. func floatToUint8(x float32) uint8 {
  4. // Nearest-neighbor values are always
  5. // positive no need to check lower-bound.
  6. if x > 0xfe {
  7. return 0xff
  8. }
  9. return uint8(x)
  10. }
  11. func floatToUint16(x float32) uint16 {
  12. if x > 0xfffe {
  13. return 0xffff
  14. }
  15. return uint16(x)
  16. }
  17. func nearestGeneric(in image.Image, out *image.RGBA64, scale float64, coeffs []bool, offset []int, filterLength int) {
  18. oldBounds := in.Bounds()
  19. newBounds := out.Bounds()
  20. for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
  21. for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
  22. var rgba [4]float32
  23. var sum float32
  24. start := offset[y]
  25. ci := (y - newBounds.Min.Y) * filterLength
  26. for i := 0; i < filterLength; i++ {
  27. if coeffs[ci+i] {
  28. xi := start + i
  29. switch {
  30. case uint(xi) < uint(oldBounds.Max.X):
  31. break
  32. case xi >= oldBounds.Max.X:
  33. xi = oldBounds.Min.X
  34. default:
  35. xi = oldBounds.Max.X - 1
  36. }
  37. r, g, b, a := in.At(xi, x).RGBA()
  38. rgba[0] += float32(r)
  39. rgba[1] += float32(g)
  40. rgba[2] += float32(b)
  41. rgba[3] += float32(a)
  42. sum++
  43. }
  44. }
  45. offset := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8
  46. value := floatToUint16(rgba[0] / sum)
  47. out.Pix[offset+0] = uint8(value >> 8)
  48. out.Pix[offset+1] = uint8(value)
  49. value = floatToUint16(rgba[1] / sum)
  50. out.Pix[offset+2] = uint8(value >> 8)
  51. out.Pix[offset+3] = uint8(value)
  52. value = floatToUint16(rgba[2] / sum)
  53. out.Pix[offset+4] = uint8(value >> 8)
  54. out.Pix[offset+5] = uint8(value)
  55. value = floatToUint16(rgba[3] / sum)
  56. out.Pix[offset+6] = uint8(value >> 8)
  57. out.Pix[offset+7] = uint8(value)
  58. }
  59. }
  60. }
  61. func nearestRGBA(in *image.RGBA, out *image.RGBA, scale float64, coeffs []bool, offset []int, filterLength int) {
  62. oldBounds := in.Bounds()
  63. newBounds := out.Bounds()
  64. minX := oldBounds.Min.X * 4
  65. maxX := (oldBounds.Max.X - oldBounds.Min.X - 1) * 4
  66. for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
  67. row := in.Pix[(x-oldBounds.Min.Y)*in.Stride:]
  68. for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
  69. var rgba [4]float32
  70. var sum float32
  71. start := offset[y]
  72. ci := (y - newBounds.Min.Y) * filterLength
  73. for i := 0; i < filterLength; i++ {
  74. if coeffs[ci+i] {
  75. xi := start + i
  76. switch {
  77. case uint(xi) < uint(oldBounds.Max.X):
  78. xi *= 4
  79. case xi >= oldBounds.Max.X:
  80. xi = maxX
  81. default:
  82. xi = minX
  83. }
  84. rgba[0] += float32(row[xi+0])
  85. rgba[1] += float32(row[xi+1])
  86. rgba[2] += float32(row[xi+2])
  87. rgba[3] += float32(row[xi+3])
  88. sum++
  89. }
  90. }
  91. xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*4
  92. out.Pix[xo+0] = floatToUint8(rgba[0] / sum)
  93. out.Pix[xo+1] = floatToUint8(rgba[1] / sum)
  94. out.Pix[xo+2] = floatToUint8(rgba[2] / sum)
  95. out.Pix[xo+3] = floatToUint8(rgba[3] / sum)
  96. }
  97. }
  98. }
  99. func nearestRGBA64(in *image.RGBA64, out *image.RGBA64, scale float64, coeffs []bool, offset []int, filterLength int) {
  100. oldBounds := in.Bounds()
  101. newBounds := out.Bounds()
  102. minX := oldBounds.Min.X * 8
  103. maxX := (oldBounds.Max.X - oldBounds.Min.X - 1) * 8
  104. for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
  105. row := in.Pix[(x-oldBounds.Min.Y)*in.Stride:]
  106. for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
  107. var rgba [4]float32
  108. var sum float32
  109. start := offset[y]
  110. ci := (y - newBounds.Min.Y) * filterLength
  111. for i := 0; i < filterLength; i++ {
  112. if coeffs[ci+i] {
  113. xi := start + i
  114. switch {
  115. case uint(xi) < uint(oldBounds.Max.X):
  116. xi *= 8
  117. case xi >= oldBounds.Max.X:
  118. xi = maxX
  119. default:
  120. xi = minX
  121. }
  122. rgba[0] += float32(uint16(row[xi+0])<<8 | uint16(row[xi+1]))
  123. rgba[1] += float32(uint16(row[xi+2])<<8 | uint16(row[xi+3]))
  124. rgba[2] += float32(uint16(row[xi+4])<<8 | uint16(row[xi+5]))
  125. rgba[3] += float32(uint16(row[xi+6])<<8 | uint16(row[xi+7]))
  126. sum++
  127. }
  128. }
  129. xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8
  130. value := floatToUint16(rgba[0] / sum)
  131. out.Pix[xo+0] = uint8(value >> 8)
  132. out.Pix[xo+1] = uint8(value)
  133. value = floatToUint16(rgba[1] / sum)
  134. out.Pix[xo+2] = uint8(value >> 8)
  135. out.Pix[xo+3] = uint8(value)
  136. value = floatToUint16(rgba[2] / sum)
  137. out.Pix[xo+4] = uint8(value >> 8)
  138. out.Pix[xo+5] = uint8(value)
  139. value = floatToUint16(rgba[3] / sum)
  140. out.Pix[xo+6] = uint8(value >> 8)
  141. out.Pix[xo+7] = uint8(value)
  142. }
  143. }
  144. }
  145. func nearestGray(in *image.Gray, out *image.Gray, scale float64, coeffs []bool, offset []int, filterLength int) {
  146. oldBounds := in.Bounds()
  147. newBounds := out.Bounds()
  148. minX := oldBounds.Min.X
  149. maxX := (oldBounds.Max.X - oldBounds.Min.X - 1)
  150. for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
  151. row := in.Pix[(x-oldBounds.Min.Y)*in.Stride:]
  152. for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
  153. var gray float32
  154. var sum float32
  155. start := offset[y]
  156. ci := (y - newBounds.Min.Y) * filterLength
  157. for i := 0; i < filterLength; i++ {
  158. if coeffs[ci+i] {
  159. xi := start + i
  160. switch {
  161. case uint(xi) < uint(oldBounds.Max.X):
  162. break
  163. case xi >= oldBounds.Max.X:
  164. xi = maxX
  165. default:
  166. xi = minX
  167. }
  168. gray += float32(row[xi])
  169. sum++
  170. }
  171. }
  172. offset := (y-newBounds.Min.Y)*out.Stride + (x - newBounds.Min.X)
  173. out.Pix[offset] = floatToUint8(gray / sum)
  174. }
  175. }
  176. }
  177. func nearestGray16(in *image.Gray16, out *image.Gray16, scale float64, coeffs []bool, offset []int, filterLength int) {
  178. oldBounds := in.Bounds()
  179. newBounds := out.Bounds()
  180. minX := oldBounds.Min.X * 2
  181. maxX := (oldBounds.Max.X - oldBounds.Min.X - 1) * 2
  182. for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
  183. row := in.Pix[(x-oldBounds.Min.Y)*in.Stride:]
  184. for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
  185. var gray float32
  186. var sum float32
  187. start := offset[y]
  188. ci := (y - newBounds.Min.Y) * filterLength
  189. for i := 0; i < filterLength; i++ {
  190. if coeffs[ci+i] {
  191. xi := start + i
  192. switch {
  193. case uint(xi) < uint(oldBounds.Max.X):
  194. xi *= 2
  195. case xi >= oldBounds.Max.X:
  196. xi = maxX
  197. default:
  198. xi = minX
  199. }
  200. gray += float32(uint16(row[xi+0])<<8 | uint16(row[xi+1]))
  201. sum++
  202. }
  203. }
  204. offset := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*2
  205. value := floatToUint16(gray / sum)
  206. out.Pix[offset+0] = uint8(value >> 8)
  207. out.Pix[offset+1] = uint8(value)
  208. }
  209. }
  210. }