Scale.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. /* eslint-disable */
  2. const HAS_ALPHA = true
  3. function scale(scale, input, output, inputRemovable) {
  4. if (!input) {
  5. input = scale.input
  6. output = scale.output
  7. inputRemovable = scale.inputRemovable
  8. if (scale.scale) scale = scale.scale
  9. }
  10. var canvas, ctx
  11. if (input.src) {
  12. canvas = document.createElement('canvas')
  13. if (input.naturalWidth != null) {
  14. canvas.width = input.naturalWidth
  15. canvas.height = input.naturalHeight
  16. } else if (input.runtimeStyle != null) {
  17. var runtimeStyle = input.runtimeStyle
  18. , mw = runtimeStyle.width, mh = runtimeStyle.height
  19. runtimeStyle.width = 'auto'
  20. runtimeStyle.height = 'auto'
  21. canvas.width = input.width
  22. canvas.height = input.height
  23. runtimeStyle.width = mw
  24. runtimeStyle.height = mh
  25. } else {
  26. var mw = input.width, mh = input.height
  27. if (input.removeAttribute) {
  28. input.removeAttribute('width')
  29. input.removeAttribute('height')
  30. }
  31. canvas.width = input.width
  32. canvas.height = input.height
  33. input.width = mw
  34. input.height = mh
  35. }
  36. } else {
  37. canvas = input
  38. }
  39. ctx = canvas.getContext('2d')
  40. if (input.src) ctx.drawImage(input, 0, 0)
  41. var sw = canvas.width, sh = canvas.height
  42. , dw, dh
  43. , sourceBuffer = ctx.getImageData(0, 0, sw, sh).data
  44. if (!sw || !sh) return false
  45. if (input.src || inputRemovable) {
  46. ctx.clearRect(0, 0, sw, sh)
  47. }
  48. if (typeof scale === 'object') {
  49. if (scale.width) {
  50. dw = scale.width + 0.5 | 0
  51. dh = scale.height + 0.5 | 0
  52. } else {
  53. dw = sw * scale.scaleX + 0.5 | 0
  54. dh = sh * scale.scaleY + 0.5 | 0
  55. }
  56. } else {
  57. dw = scale * sw + 0.5 | 0
  58. dh = scale * sh + 0.5 | 0
  59. }
  60. var dw4 = dw << 2
  61. , sw4 = sw << 2
  62. , sx, sy, sindex = 0
  63. , dx, dy, dyindex, dindex = 0
  64. , idx, idy, isx, isy
  65. , w, wx, nwx, wy, nwy
  66. , crossX, crossY
  67. , dwh4 = dw4 * dh
  68. , tmpBuffer
  69. , r, g, b, a
  70. , dsy, dsx
  71. , newCanvas, newCtx, imageData, byteBuffer
  72. , TIMES = 255.99 / 255
  73. , row0, row1, row2, row3
  74. , col0, col1, col2, col3
  75. , scaleX = dw / sw
  76. , scaleY = dh / sh
  77. , scaleXY = scaleX * scaleY
  78. function setNewCanvas() {
  79. // CREATE downscale canvas
  80. if (typeof output === 'object') {
  81. newCanvas = output
  82. } else if (input.src || inputRemovable) {
  83. newCanvas = canvas
  84. } else {
  85. newCanvas = document.createElement('canvas')
  86. }
  87. newCanvas.width = dw
  88. newCanvas.height = dh
  89. newCtx = newCanvas.getContext('2d')
  90. }
  91. function getImageData(tmpBuffer) {
  92. if (!tmpBuffer) {
  93. return newCtx.getImageData(0, 0, dw, dh)
  94. } else {
  95. var imageData = newCtx.getImageData(0, 0, dw, dh)
  96. , byteBuffer = imageData.data
  97. , dindex
  98. for (dindex = 0; dindex < dwh4; dindex += 4) {
  99. byteBuffer[dindex] = tmpBuffer[dindex] * TIMES | 0
  100. byteBuffer[dindex + 1] = tmpBuffer[dindex + 1] * TIMES | 0
  101. byteBuffer[dindex + 2] = tmpBuffer[dindex + 2] * TIMES | 0
  102. byteBuffer[dindex + 3] = HAS_ALPHA ? tmpBuffer[dindex + 3] * TIMES | 0 : 255
  103. }
  104. // delete tmpBuffer
  105. return imageData
  106. }
  107. }
  108. if (scaleX > 1 || scaleY > 1) {
  109. // UPSCALE by bicubic
  110. function bicubic(t, a, b, c, d) {
  111. return 0.5 * (c - a + (2 * a - 5 * b + 4 * c - d + (3 * (b - c) + d - a) * t) * t) * t + b
  112. }
  113. setNewCanvas()
  114. imageData = getImageData()
  115. byteBuffer = imageData.data
  116. for (dy = 0; dy < dh; dy++) {
  117. sy = dy / scaleY
  118. isy = sy | 0
  119. dsy = sy - isy
  120. row1 = isy * sw4
  121. row0 = isy < 1 ? row1 : row1 - sw4
  122. if (isy < sh - 2) {
  123. row2 = row1 + sw4
  124. row3 = (isy + 2) * sw4
  125. } else {
  126. row2 = row3 = isy > sh - 2 ? row1 : row1 + sw4
  127. }
  128. for (dx = 0; dx < dw; dx++ , dindex += 4) {
  129. sx = dx / scaleX
  130. isx = sx | 0
  131. dsx = sx - isx
  132. col1 = isx << 2
  133. col0 = isx < 1 ? col1 : col1 - 4
  134. if (isx < sw - 2) {
  135. col2 = col1 + 4
  136. col3 = col1 + 8
  137. } else {
  138. col2 = col3 = isx > sw - 2 ? col1 : col1 + 4
  139. }
  140. // RED
  141. r = bicubic(dsy,
  142. bicubic(dsx
  143. , sourceBuffer[row0 + col0]
  144. , sourceBuffer[row0 + col1]
  145. , sourceBuffer[row0 + col2]
  146. , sourceBuffer[row0 + col3]
  147. )
  148. , bicubic(dsx
  149. , sourceBuffer[row1 + col0]
  150. , sourceBuffer[row1 + col1]
  151. , sourceBuffer[row1 + col2]
  152. , sourceBuffer[row1 + col3]
  153. )
  154. , bicubic(dsx
  155. , sourceBuffer[row2 + col0]
  156. , sourceBuffer[row2 + col1]
  157. , sourceBuffer[row2 + col2]
  158. , sourceBuffer[row2 + col3]
  159. )
  160. , bicubic(dsx
  161. , sourceBuffer[row3 + col0]
  162. , sourceBuffer[row3 + col1]
  163. , sourceBuffer[row3 + col2]
  164. , sourceBuffer[row3 + col3]
  165. )
  166. ) * TIMES | 0
  167. // GREEN
  168. ++col0, ++col1, ++col2, ++col3
  169. g = bicubic(dsy,
  170. bicubic(dsx
  171. , sourceBuffer[row0 + col0]
  172. , sourceBuffer[row0 + col1]
  173. , sourceBuffer[row0 + col2]
  174. , sourceBuffer[row0 + col3]
  175. )
  176. , bicubic(dsx
  177. , sourceBuffer[row1 + col0]
  178. , sourceBuffer[row1 + col1]
  179. , sourceBuffer[row1 + col2]
  180. , sourceBuffer[row1 + col3]
  181. )
  182. , bicubic(dsx
  183. , sourceBuffer[row2 + col0]
  184. , sourceBuffer[row2 + col1]
  185. , sourceBuffer[row2 + col2]
  186. , sourceBuffer[row2 + col3]
  187. )
  188. , bicubic(dsx
  189. , sourceBuffer[row3 + col0]
  190. , sourceBuffer[row3 + col1]
  191. , sourceBuffer[row3 + col2]
  192. , sourceBuffer[row3 + col3]
  193. )
  194. ) * TIMES | 0
  195. // BLUE
  196. ++col0, ++col1, ++col2, ++col3
  197. b = bicubic(dsy,
  198. bicubic(dsx
  199. , sourceBuffer[row0 + col0]
  200. , sourceBuffer[row0 + col1]
  201. , sourceBuffer[row0 + col2]
  202. , sourceBuffer[row0 + col3]
  203. )
  204. , bicubic(dsx
  205. , sourceBuffer[row1 + col0]
  206. , sourceBuffer[row1 + col1]
  207. , sourceBuffer[row1 + col2]
  208. , sourceBuffer[row1 + col3]
  209. )
  210. , bicubic(dsx
  211. , sourceBuffer[row2 + col0]
  212. , sourceBuffer[row2 + col1]
  213. , sourceBuffer[row2 + col2]
  214. , sourceBuffer[row2 + col3]
  215. )
  216. , bicubic(dsx
  217. , sourceBuffer[row3 + col0]
  218. , sourceBuffer[row3 + col1]
  219. , sourceBuffer[row3 + col2]
  220. , sourceBuffer[row3 + col3]
  221. )
  222. ) * TIMES | 0
  223. byteBuffer[dindex] = r >= 0 ? r < 256 ? r : 255 : 0
  224. byteBuffer[dindex + 1] = g >= 0 ? g < 256 ? g : 255 : 0
  225. byteBuffer[dindex + 2] = b >= 0 ? b < 256 ? b : 255 : 0
  226. if (HAS_ALPHA) {
  227. // ALPHA
  228. ++col0, ++col1, ++col2, ++col3
  229. a = bicubic(dsy,
  230. bicubic(dsx
  231. , sourceBuffer[row0 + col0]
  232. , sourceBuffer[row0 + col1]
  233. , sourceBuffer[row0 + col2]
  234. , sourceBuffer[row0 + col3]
  235. )
  236. , bicubic(dsx
  237. , sourceBuffer[row1 + col0]
  238. , sourceBuffer[row1 + col1]
  239. , sourceBuffer[row1 + col2]
  240. , sourceBuffer[row1 + col3]
  241. )
  242. , bicubic(dsx
  243. , sourceBuffer[row2 + col0]
  244. , sourceBuffer[row2 + col1]
  245. , sourceBuffer[row2 + col2]
  246. , sourceBuffer[row2 + col3]
  247. )
  248. , bicubic(dsx
  249. , sourceBuffer[row3 + col0]
  250. , sourceBuffer[row3 + col1]
  251. , sourceBuffer[row3 + col2]
  252. , sourceBuffer[row3 + col3]
  253. )
  254. ) * TIMES | 0
  255. byteBuffer[dindex + 3] = a >= 0 ? a < 256 ? a : 255 : 0
  256. } else {
  257. byteBuffer[dindex + 3] = 255
  258. }
  259. }
  260. }
  261. } else {
  262. // DOWNSCALE
  263. if (root.Float32Array) {
  264. tmpBuffer = new Float32Array(dwh4)
  265. } else {
  266. tmpBuffer = []
  267. for (dindex = 0; dindex < dwh4; ++dindex) {
  268. tmpBuffer[dindex] = 0
  269. }
  270. }
  271. // CREATE float buffer
  272. for (sy = 0; sy < sh; sy++) {
  273. dy = sy * scaleY
  274. idy = dy | 0
  275. dyindex = idy * dw4
  276. crossY = (!!((idy - (dy + scaleY | 0)) * (sh - 1 - sy))) << 1
  277. if (crossY) {
  278. wy = idy + 1 - dy
  279. nwy = dy + scaleY - idy - 1
  280. }
  281. for (sx = 0; sx < sw; sx++ , sindex += 4) {
  282. dx = sx * scaleX
  283. idx = dx | 0
  284. dindex = dyindex + (idx << 2)
  285. crossX = !!((idx - (dx + scaleX | 0)) * (sw - 1 - sx))
  286. if (crossX) {
  287. wx = idx + 1 - dx
  288. nwx = dx + scaleX - idx - 1
  289. }
  290. r = sourceBuffer[sindex]
  291. g = sourceBuffer[sindex + 1]
  292. b = sourceBuffer[sindex + 2]
  293. if (HAS_ALPHA) a = sourceBuffer[sindex + 3]
  294. switch (crossX + crossY) {
  295. case 0:
  296. tmpBuffer[dindex] += r * scaleXY
  297. tmpBuffer[dindex + 1] += g * scaleXY
  298. tmpBuffer[dindex + 2] += b * scaleXY
  299. if (HAS_ALPHA) tmpBuffer[dindex + 3] += a * scaleXY
  300. break
  301. case 1:
  302. w = wx * scaleY
  303. tmpBuffer[dindex] += r * w
  304. tmpBuffer[dindex + 1] += g * w
  305. tmpBuffer[dindex + 2] += b * w
  306. if (HAS_ALPHA) tmpBuffer[dindex + 3] += a * w
  307. w = nwx * scaleY
  308. tmpBuffer[dindex + 4] += r * w
  309. tmpBuffer[dindex + 5] += g * w
  310. tmpBuffer[dindex + 6] += b * w
  311. if (HAS_ALPHA) tmpBuffer[dindex + 7] += a * w
  312. break
  313. case 2:
  314. w = scaleX * wy
  315. tmpBuffer[dindex] += r * w
  316. tmpBuffer[dindex + 1] += g * w
  317. tmpBuffer[dindex + 2] += b * w
  318. if (HAS_ALPHA) tmpBuffer[dindex + 3] += a * w
  319. w = scaleX * nwy
  320. dindex += dw4
  321. tmpBuffer[dindex] += r * w
  322. tmpBuffer[dindex + 1] += g * w
  323. tmpBuffer[dindex + 2] += b * w
  324. if (HAS_ALPHA) tmpBuffer[dindex + 3] += a * w
  325. break
  326. default:
  327. w = wx * wy
  328. tmpBuffer[dindex] += r * w
  329. tmpBuffer[dindex + 1] += g * w
  330. tmpBuffer[dindex + 2] += b * w
  331. if (HAS_ALPHA) tmpBuffer[dindex + 3] += a * w
  332. w = nwx * wy
  333. tmpBuffer[dindex + 4] += r * w
  334. tmpBuffer[dindex + 5] += g * w
  335. tmpBuffer[dindex + 6] += b * w
  336. if (HAS_ALPHA) tmpBuffer[dindex + 7] += a * w
  337. w = wx * nwy
  338. dindex += dw4
  339. tmpBuffer[dindex] += r * w
  340. tmpBuffer[dindex + 1] += g * w
  341. tmpBuffer[dindex + 2] += b * w
  342. if (HAS_ALPHA) tmpBuffer[dindex + 3] += a * w
  343. w = nwx * nwy
  344. tmpBuffer[dindex + 4] += r * w
  345. tmpBuffer[dindex + 5] += g * w
  346. tmpBuffer[dindex + 6] += b * w
  347. if (HAS_ALPHA) tmpBuffer[dindex + 7] += a * w
  348. break
  349. }
  350. }
  351. }
  352. // delete sourceBuffer
  353. setNewCanvas()
  354. imageData = getImageData(tmpBuffer)
  355. }
  356. newCtx.putImageData(imageData, 0, 0)
  357. if (typeof output === 'string') {
  358. if (output === 'png' || output === 'jpeg') {
  359. var img
  360. if (inputRemovable && input.src) {
  361. img = input
  362. } else {
  363. img = new Image()
  364. }
  365. img.width = dw
  366. img.height = dh
  367. img.src = newCanvas.toDataURL('image/' + output, 1)
  368. return img
  369. } else if (output === 'png-src' || output === 'jpeg-src') {
  370. return newCanvas.toDataURL('image/' + output.split('-')[0], 1)
  371. }
  372. }
  373. return newCanvas
  374. }
  375. module.exports = scale;