load-image-scale.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /*
  2. * JavaScript Load Image Scaling
  3. * https://github.com/blueimp/JavaScript-Load-Image
  4. *
  5. * Copyright 2011, Sebastian Tschan
  6. * https://blueimp.net
  7. *
  8. * Licensed under the MIT license:
  9. * https://opensource.org/licenses/MIT
  10. */
  11. /* global define */
  12. ;(function (factory) {
  13. 'use strict'
  14. if (typeof define === 'function' && define.amd) {
  15. // Register as an anonymous AMD module:
  16. define(['./load-image'], factory)
  17. } else if (typeof module === 'object' && module.exports) {
  18. factory(require('./load-image'))
  19. } else {
  20. // Browser globals:
  21. factory(window.loadImage)
  22. }
  23. })(function (loadImage) {
  24. 'use strict'
  25. var originalTransform = loadImage.transform
  26. loadImage.transform = function (img, options, callback, file, data) {
  27. originalTransform.call(
  28. loadImage,
  29. loadImage.scale(img, options, data),
  30. options,
  31. callback,
  32. file,
  33. data
  34. )
  35. }
  36. // Transform image coordinates, allows to override e.g.
  37. // the canvas orientation based on the orientation option,
  38. // gets canvas, options passed as arguments:
  39. loadImage.transformCoordinates = function () {}
  40. // Returns transformed options, allows to override e.g.
  41. // maxWidth, maxHeight and crop options based on the aspectRatio.
  42. // gets img, options passed as arguments:
  43. loadImage.getTransformedOptions = function (img, options) {
  44. var aspectRatio = options.aspectRatio
  45. var newOptions
  46. var i
  47. var width
  48. var height
  49. if (!aspectRatio) {
  50. return options
  51. }
  52. newOptions = {}
  53. for (i in options) {
  54. if (options.hasOwnProperty(i)) {
  55. newOptions[i] = options[i]
  56. }
  57. }
  58. newOptions.crop = true
  59. width = img.naturalWidth || img.width
  60. height = img.naturalHeight || img.height
  61. if (width / height > aspectRatio) {
  62. newOptions.maxWidth = height * aspectRatio
  63. newOptions.maxHeight = height
  64. } else {
  65. newOptions.maxWidth = width
  66. newOptions.maxHeight = width / aspectRatio
  67. }
  68. return newOptions
  69. }
  70. // Canvas render method, allows to implement a different rendering algorithm:
  71. loadImage.renderImageToCanvas = function (
  72. canvas,
  73. img,
  74. sourceX,
  75. sourceY,
  76. sourceWidth,
  77. sourceHeight,
  78. destX,
  79. destY,
  80. destWidth,
  81. destHeight
  82. ) {
  83. canvas
  84. .getContext('2d')
  85. .drawImage(
  86. img,
  87. sourceX,
  88. sourceY,
  89. sourceWidth,
  90. sourceHeight,
  91. destX,
  92. destY,
  93. destWidth,
  94. destHeight
  95. )
  96. return canvas
  97. }
  98. // Determines if the target image should be a canvas element:
  99. loadImage.hasCanvasOption = function (options) {
  100. return options.canvas || options.crop || !!options.aspectRatio
  101. }
  102. // Scales and/or crops the given image (img or canvas HTML element)
  103. // using the given options.
  104. // Returns a canvas object if the browser supports canvas
  105. // and the hasCanvasOption method returns true or a canvas
  106. // object is passed as image, else the scaled image:
  107. loadImage.scale = function (img, options, data) {
  108. options = options || {}
  109. var canvas = document.createElement('canvas')
  110. var useCanvas =
  111. img.getContext ||
  112. (loadImage.hasCanvasOption(options) && canvas.getContext)
  113. var width = img.naturalWidth || img.width
  114. var height = img.naturalHeight || img.height
  115. var destWidth = width
  116. var destHeight = height
  117. var maxWidth
  118. var maxHeight
  119. var minWidth
  120. var minHeight
  121. var sourceWidth
  122. var sourceHeight
  123. var sourceX
  124. var sourceY
  125. var pixelRatio
  126. var downsamplingRatio
  127. var tmp
  128. function scaleUp () {
  129. var scale = Math.max(
  130. (minWidth || destWidth) / destWidth,
  131. (minHeight || destHeight) / destHeight
  132. )
  133. if (scale > 1) {
  134. destWidth *= scale
  135. destHeight *= scale
  136. }
  137. }
  138. function scaleDown () {
  139. var scale = Math.min(
  140. (maxWidth || destWidth) / destWidth,
  141. (maxHeight || destHeight) / destHeight
  142. )
  143. if (scale < 1) {
  144. destWidth *= scale
  145. destHeight *= scale
  146. }
  147. }
  148. if (useCanvas) {
  149. options = loadImage.getTransformedOptions(img, options, data)
  150. sourceX = options.left || 0
  151. sourceY = options.top || 0
  152. if (options.sourceWidth) {
  153. sourceWidth = options.sourceWidth
  154. if (options.right !== undefined && options.left === undefined) {
  155. sourceX = width - sourceWidth - options.right
  156. }
  157. } else {
  158. sourceWidth = width - sourceX - (options.right || 0)
  159. }
  160. if (options.sourceHeight) {
  161. sourceHeight = options.sourceHeight
  162. if (options.bottom !== undefined && options.top === undefined) {
  163. sourceY = height - sourceHeight - options.bottom
  164. }
  165. } else {
  166. sourceHeight = height - sourceY - (options.bottom || 0)
  167. }
  168. destWidth = sourceWidth
  169. destHeight = sourceHeight
  170. }
  171. maxWidth = options.maxWidth
  172. maxHeight = options.maxHeight
  173. minWidth = options.minWidth
  174. minHeight = options.minHeight
  175. if (useCanvas && maxWidth && maxHeight && options.crop) {
  176. destWidth = maxWidth
  177. destHeight = maxHeight
  178. tmp = sourceWidth / sourceHeight - maxWidth / maxHeight
  179. if (tmp < 0) {
  180. sourceHeight = maxHeight * sourceWidth / maxWidth
  181. if (options.top === undefined && options.bottom === undefined) {
  182. sourceY = (height - sourceHeight) / 2
  183. }
  184. } else if (tmp > 0) {
  185. sourceWidth = maxWidth * sourceHeight / maxHeight
  186. if (options.left === undefined && options.right === undefined) {
  187. sourceX = (width - sourceWidth) / 2
  188. }
  189. }
  190. } else {
  191. if (options.contain || options.cover) {
  192. minWidth = maxWidth = maxWidth || minWidth
  193. minHeight = maxHeight = maxHeight || minHeight
  194. }
  195. if (options.cover) {
  196. scaleDown()
  197. scaleUp()
  198. } else {
  199. scaleUp()
  200. scaleDown()
  201. }
  202. }
  203. if (useCanvas) {
  204. pixelRatio = options.pixelRatio
  205. if (pixelRatio > 1) {
  206. canvas.style.width = destWidth + 'px'
  207. canvas.style.height = destHeight + 'px'
  208. destWidth *= pixelRatio
  209. destHeight *= pixelRatio
  210. canvas.getContext('2d').scale(pixelRatio, pixelRatio)
  211. }
  212. downsamplingRatio = options.downsamplingRatio
  213. if (
  214. downsamplingRatio > 0 &&
  215. downsamplingRatio < 1 &&
  216. destWidth < sourceWidth &&
  217. destHeight < sourceHeight
  218. ) {
  219. while (sourceWidth * downsamplingRatio > destWidth) {
  220. canvas.width = sourceWidth * downsamplingRatio
  221. canvas.height = sourceHeight * downsamplingRatio
  222. loadImage.renderImageToCanvas(
  223. canvas,
  224. img,
  225. sourceX,
  226. sourceY,
  227. sourceWidth,
  228. sourceHeight,
  229. 0,
  230. 0,
  231. canvas.width,
  232. canvas.height
  233. )
  234. sourceX = 0
  235. sourceY = 0
  236. sourceWidth = canvas.width
  237. sourceHeight = canvas.height
  238. img = document.createElement('canvas')
  239. img.width = sourceWidth
  240. img.height = sourceHeight
  241. loadImage.renderImageToCanvas(
  242. img,
  243. canvas,
  244. 0,
  245. 0,
  246. sourceWidth,
  247. sourceHeight,
  248. 0,
  249. 0,
  250. sourceWidth,
  251. sourceHeight
  252. )
  253. }
  254. }
  255. canvas.width = destWidth
  256. canvas.height = destHeight
  257. loadImage.transformCoordinates(canvas, options)
  258. return loadImage.renderImageToCanvas(
  259. canvas,
  260. img,
  261. sourceX,
  262. sourceY,
  263. sourceWidth,
  264. sourceHeight,
  265. 0,
  266. 0,
  267. destWidth,
  268. destHeight
  269. )
  270. }
  271. img.width = destWidth
  272. img.height = destHeight
  273. return img
  274. }
  275. })