converter.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. /*
  2. Copyright (c) 2012, Jan Schlicht <jan.schlicht@gmail.com>
  3. Permission to use, copy, modify, and/or distribute this software for any purpose
  4. with or without fee is hereby granted, provided that the above copyright notice
  5. and this permission notice appear in all copies.
  6. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
  7. REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  8. FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  9. INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
  10. OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  11. TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
  12. THIS SOFTWARE.
  13. */
  14. package resize
  15. import "image"
  16. // Keep value in [0,255] range.
  17. func clampUint8(in int32) uint8 {
  18. // casting a negative int to an uint will result in an overflown
  19. // large uint. this behavior will be exploited here and in other functions
  20. // to achieve a higher performance.
  21. if uint32(in) < 256 {
  22. return uint8(in)
  23. }
  24. if in > 255 {
  25. return 255
  26. }
  27. return 0
  28. }
  29. // Keep value in [0,65535] range.
  30. func clampUint16(in int64) uint16 {
  31. if uint64(in) < 65536 {
  32. return uint16(in)
  33. }
  34. if in > 65535 {
  35. return 65535
  36. }
  37. return 0
  38. }
  39. func resizeGeneric(in image.Image, out *image.NRGBA64, scale float64, coeffs []int32, offset []int, filterLength int) {
  40. newBounds := out.Bounds()
  41. maxX := in.Bounds().Dx() - 1
  42. for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
  43. for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
  44. var rgba [4]int64
  45. var sum int64
  46. start := offset[y]
  47. ci := y * filterLength
  48. for i := 0; i < filterLength; i++ {
  49. coeff := coeffs[ci+i]
  50. if coeff != 0 {
  51. xi := start + i
  52. switch {
  53. case xi < 0:
  54. xi = 0
  55. case xi >= maxX:
  56. xi = maxX
  57. }
  58. r, g, b, a := in.At(xi+in.Bounds().Min.X, x+in.Bounds().Min.Y).RGBA()
  59. // reverse alpha-premultiplication.
  60. if a != 0 {
  61. r *= 0xffff
  62. r /= a
  63. g *= 0xffff
  64. g /= a
  65. b *= 0xffff
  66. b /= a
  67. }
  68. rgba[0] += int64(coeff) * int64(r)
  69. rgba[1] += int64(coeff) * int64(g)
  70. rgba[2] += int64(coeff) * int64(b)
  71. rgba[3] += int64(coeff) * int64(a)
  72. sum += int64(coeff)
  73. }
  74. }
  75. offset := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8
  76. value := clampUint16(rgba[0] / sum)
  77. out.Pix[offset+0] = uint8(value >> 8)
  78. out.Pix[offset+1] = uint8(value)
  79. value = clampUint16(rgba[1] / sum)
  80. out.Pix[offset+2] = uint8(value >> 8)
  81. out.Pix[offset+3] = uint8(value)
  82. value = clampUint16(rgba[2] / sum)
  83. out.Pix[offset+4] = uint8(value >> 8)
  84. out.Pix[offset+5] = uint8(value)
  85. value = clampUint16(rgba[3] / sum)
  86. out.Pix[offset+6] = uint8(value >> 8)
  87. out.Pix[offset+7] = uint8(value)
  88. }
  89. }
  90. }
  91. func resizeRGBA(in *image.RGBA, out *image.NRGBA, scale float64, coeffs []int16, offset []int, filterLength int) {
  92. newBounds := out.Bounds()
  93. maxX := in.Bounds().Dx() - 1
  94. for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
  95. row := in.Pix[x*in.Stride:]
  96. for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
  97. var rgba [4]int32
  98. var sum int32
  99. start := offset[y]
  100. ci := y * filterLength
  101. for i := 0; i < filterLength; i++ {
  102. coeff := coeffs[ci+i]
  103. if coeff != 0 {
  104. xi := start + i
  105. switch {
  106. case uint(xi) < uint(maxX):
  107. xi *= 4
  108. case xi >= maxX:
  109. xi = 4 * maxX
  110. default:
  111. xi = 0
  112. }
  113. r := uint32(row[xi+0])
  114. g := uint32(row[xi+1])
  115. b := uint32(row[xi+2])
  116. a := uint32(row[xi+3])
  117. // reverse alpha-premultiplication.
  118. if a != 0 {
  119. r *= 0xffff
  120. r /= a
  121. g *= 0xffff
  122. g /= a
  123. b *= 0xffff
  124. b /= a
  125. }
  126. rgba[0] += int32(coeff) * int32(r)
  127. rgba[1] += int32(coeff) * int32(g)
  128. rgba[2] += int32(coeff) * int32(b)
  129. rgba[3] += int32(coeff) * int32(a)
  130. sum += int32(coeff)
  131. }
  132. }
  133. xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*4
  134. out.Pix[xo+0] = clampUint8(rgba[0] / sum)
  135. out.Pix[xo+1] = clampUint8(rgba[1] / sum)
  136. out.Pix[xo+2] = clampUint8(rgba[2] / sum)
  137. out.Pix[xo+3] = clampUint8(rgba[3] / sum)
  138. }
  139. }
  140. }
  141. func resizeNRGBA(in *image.NRGBA, out *image.NRGBA, scale float64, coeffs []int16, offset []int, filterLength int) {
  142. newBounds := out.Bounds()
  143. maxX := in.Bounds().Dx() - 1
  144. for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
  145. row := in.Pix[x*in.Stride:]
  146. for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
  147. var rgba [4]int32
  148. var sum int32
  149. start := offset[y]
  150. ci := y * filterLength
  151. for i := 0; i < filterLength; i++ {
  152. coeff := coeffs[ci+i]
  153. if coeff != 0 {
  154. xi := start + i
  155. switch {
  156. case uint(xi) < uint(maxX):
  157. xi *= 4
  158. case xi >= maxX:
  159. xi = 4 * maxX
  160. default:
  161. xi = 0
  162. }
  163. rgba[0] += int32(coeff) * int32(row[xi+0])
  164. rgba[1] += int32(coeff) * int32(row[xi+1])
  165. rgba[2] += int32(coeff) * int32(row[xi+2])
  166. rgba[3] += int32(coeff) * int32(row[xi+3])
  167. sum += int32(coeff)
  168. }
  169. }
  170. xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*4
  171. out.Pix[xo+0] = clampUint8(rgba[0] / sum)
  172. out.Pix[xo+1] = clampUint8(rgba[1] / sum)
  173. out.Pix[xo+2] = clampUint8(rgba[2] / sum)
  174. out.Pix[xo+3] = clampUint8(rgba[3] / sum)
  175. }
  176. }
  177. }
  178. func resizeRGBA64(in *image.RGBA64, out *image.NRGBA64, scale float64, coeffs []int32, offset []int, filterLength int) {
  179. newBounds := out.Bounds()
  180. maxX := in.Bounds().Dx() - 1
  181. for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
  182. row := in.Pix[x*in.Stride:]
  183. for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
  184. var rgba [4]int64
  185. var sum int64
  186. start := offset[y]
  187. ci := y * filterLength
  188. for i := 0; i < filterLength; i++ {
  189. coeff := coeffs[ci+i]
  190. if coeff != 0 {
  191. xi := start + i
  192. switch {
  193. case uint(xi) < uint(maxX):
  194. xi *= 8
  195. case xi >= maxX:
  196. xi = 8 * maxX
  197. default:
  198. xi = 0
  199. }
  200. r := uint32(uint16(row[xi+0])<<8 | uint16(row[xi+1]))
  201. g := uint32(uint16(row[xi+2])<<8 | uint16(row[xi+3]))
  202. b := uint32(uint16(row[xi+4])<<8 | uint16(row[xi+5]))
  203. a := uint32(uint16(row[xi+6])<<8 | uint16(row[xi+7]))
  204. // reverse alpha-premultiplication.
  205. if a != 0 {
  206. r *= 0xffff
  207. r /= a
  208. g *= 0xffff
  209. g /= a
  210. b *= 0xffff
  211. b /= a
  212. }
  213. rgba[0] += int64(coeff) * int64(r)
  214. rgba[1] += int64(coeff) * int64(g)
  215. rgba[2] += int64(coeff) * int64(b)
  216. rgba[3] += int64(coeff) * int64(a)
  217. sum += int64(coeff)
  218. }
  219. }
  220. xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8
  221. value := clampUint16(rgba[0] / sum)
  222. out.Pix[xo+0] = uint8(value >> 8)
  223. out.Pix[xo+1] = uint8(value)
  224. value = clampUint16(rgba[1] / sum)
  225. out.Pix[xo+2] = uint8(value >> 8)
  226. out.Pix[xo+3] = uint8(value)
  227. value = clampUint16(rgba[2] / sum)
  228. out.Pix[xo+4] = uint8(value >> 8)
  229. out.Pix[xo+5] = uint8(value)
  230. value = clampUint16(rgba[3] / sum)
  231. out.Pix[xo+6] = uint8(value >> 8)
  232. out.Pix[xo+7] = uint8(value)
  233. }
  234. }
  235. }
  236. func resizeNRGBA64(in *image.NRGBA64, out *image.NRGBA64, scale float64, coeffs []int32, offset []int, filterLength int) {
  237. newBounds := out.Bounds()
  238. maxX := in.Bounds().Dx() - 1
  239. for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
  240. row := in.Pix[x*in.Stride:]
  241. for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
  242. var rgba [4]int64
  243. var sum int64
  244. start := offset[y]
  245. ci := y * filterLength
  246. for i := 0; i < filterLength; i++ {
  247. coeff := coeffs[ci+i]
  248. if coeff != 0 {
  249. xi := start + i
  250. switch {
  251. case uint(xi) < uint(maxX):
  252. xi *= 8
  253. case xi >= maxX:
  254. xi = 8 * maxX
  255. default:
  256. xi = 0
  257. }
  258. rgba[0] += int64(coeff) * int64(uint16(row[xi+0])<<8|uint16(row[xi+1]))
  259. rgba[1] += int64(coeff) * int64(uint16(row[xi+2])<<8|uint16(row[xi+3]))
  260. rgba[2] += int64(coeff) * int64(uint16(row[xi+4])<<8|uint16(row[xi+5]))
  261. rgba[3] += int64(coeff) * int64(uint16(row[xi+6])<<8|uint16(row[xi+7]))
  262. sum += int64(coeff)
  263. }
  264. }
  265. xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8
  266. value := clampUint16(rgba[0] / sum)
  267. out.Pix[xo+0] = uint8(value >> 8)
  268. out.Pix[xo+1] = uint8(value)
  269. value = clampUint16(rgba[1] / sum)
  270. out.Pix[xo+2] = uint8(value >> 8)
  271. out.Pix[xo+3] = uint8(value)
  272. value = clampUint16(rgba[2] / sum)
  273. out.Pix[xo+4] = uint8(value >> 8)
  274. out.Pix[xo+5] = uint8(value)
  275. value = clampUint16(rgba[3] / sum)
  276. out.Pix[xo+6] = uint8(value >> 8)
  277. out.Pix[xo+7] = uint8(value)
  278. }
  279. }
  280. }
  281. func resizeGray(in *image.Gray, out *image.Gray, scale float64, coeffs []int16, offset []int, filterLength int) {
  282. newBounds := out.Bounds()
  283. maxX := in.Bounds().Dx() - 1
  284. for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
  285. row := in.Pix[(x-newBounds.Min.X)*in.Stride:]
  286. for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
  287. var gray int32
  288. var sum int32
  289. start := offset[y]
  290. ci := y * filterLength
  291. for i := 0; i < filterLength; i++ {
  292. coeff := coeffs[ci+i]
  293. if coeff != 0 {
  294. xi := start + i
  295. switch {
  296. case xi < 0:
  297. xi = 0
  298. case xi >= maxX:
  299. xi = maxX
  300. }
  301. gray += int32(coeff) * int32(row[xi])
  302. sum += int32(coeff)
  303. }
  304. }
  305. offset := (y-newBounds.Min.Y)*out.Stride + (x - newBounds.Min.X)
  306. out.Pix[offset] = clampUint8(gray / sum)
  307. }
  308. }
  309. }
  310. func resizeGray16(in *image.Gray16, out *image.Gray16, scale float64, coeffs []int32, offset []int, filterLength int) {
  311. newBounds := out.Bounds()
  312. maxX := in.Bounds().Dx() - 1
  313. for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
  314. row := in.Pix[x*in.Stride:]
  315. for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
  316. var gray int64
  317. var sum int64
  318. start := offset[y]
  319. ci := y * filterLength
  320. for i := 0; i < filterLength; i++ {
  321. coeff := coeffs[ci+i]
  322. if coeff != 0 {
  323. xi := start + i
  324. switch {
  325. case uint(xi) < uint(maxX):
  326. xi *= 2
  327. case xi >= maxX:
  328. xi = 2 * maxX
  329. default:
  330. xi = 0
  331. }
  332. gray += int64(coeff) * int64(uint16(row[xi+0])<<8|uint16(row[xi+1]))
  333. sum += int64(coeff)
  334. }
  335. }
  336. offset := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*2
  337. value := clampUint16(gray / sum)
  338. out.Pix[offset+0] = uint8(value >> 8)
  339. out.Pix[offset+1] = uint8(value)
  340. }
  341. }
  342. }
  343. func resizeYCbCr(in *ycc, out *ycc, scale float64, coeffs []int16, offset []int, filterLength int) {
  344. newBounds := out.Bounds()
  345. maxX := in.Bounds().Dx() - 1
  346. for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
  347. row := in.Pix[x*in.Stride:]
  348. for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
  349. var p [3]int32
  350. var sum int32
  351. start := offset[y]
  352. ci := y * filterLength
  353. for i := 0; i < filterLength; i++ {
  354. coeff := coeffs[ci+i]
  355. if coeff != 0 {
  356. xi := start + i
  357. switch {
  358. case uint(xi) < uint(maxX):
  359. xi *= 3
  360. case xi >= maxX:
  361. xi = 3 * maxX
  362. default:
  363. xi = 0
  364. }
  365. p[0] += int32(coeff) * int32(row[xi+0])
  366. p[1] += int32(coeff) * int32(row[xi+1])
  367. p[2] += int32(coeff) * int32(row[xi+2])
  368. sum += int32(coeff)
  369. }
  370. }
  371. xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*3
  372. out.Pix[xo+0] = clampUint8(p[0] / sum)
  373. out.Pix[xo+1] = clampUint8(p[1] / sum)
  374. out.Pix[xo+2] = clampUint8(p[2] / sum)
  375. }
  376. }
  377. }
  378. func nearestYCbCr(in *ycc, out *ycc, scale float64, coeffs []bool, offset []int, filterLength int) {
  379. newBounds := out.Bounds()
  380. maxX := in.Bounds().Dx() - 1
  381. for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
  382. row := in.Pix[x*in.Stride:]
  383. for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
  384. var p [3]float32
  385. var sum float32
  386. start := offset[y]
  387. ci := y * filterLength
  388. for i := 0; i < filterLength; i++ {
  389. if coeffs[ci+i] {
  390. xi := start + i
  391. switch {
  392. case uint(xi) < uint(maxX):
  393. xi *= 3
  394. case xi >= maxX:
  395. xi = 3 * maxX
  396. default:
  397. xi = 0
  398. }
  399. p[0] += float32(row[xi+0])
  400. p[1] += float32(row[xi+1])
  401. p[2] += float32(row[xi+2])
  402. sum++
  403. }
  404. }
  405. xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*3
  406. out.Pix[xo+0] = floatToUint8(p[0] / sum)
  407. out.Pix[xo+1] = floatToUint8(p[1] / sum)
  408. out.Pix[xo+2] = floatToUint8(p[2] / sum)
  409. }
  410. }
  411. }