load-image-scale.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  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. return
  41. }
  42. // Returns transformed options, allows to override e.g.
  43. // maxWidth, maxHeight and crop options based on the aspectRatio.
  44. // gets img, options passed as arguments:
  45. loadImage.getTransformedOptions = function (img, options) {
  46. var aspectRatio = options.aspectRatio
  47. var newOptions
  48. var i
  49. var width
  50. var height
  51. if (!aspectRatio) {
  52. return options
  53. }
  54. newOptions = {}
  55. for (i in options) {
  56. if (options.hasOwnProperty(i)) {
  57. newOptions[i] = options[i]
  58. }
  59. }
  60. newOptions.crop = true
  61. width = img.naturalWidth || img.width
  62. height = img.naturalHeight || img.height
  63. if (width / height > aspectRatio) {
  64. newOptions.maxWidth = height * aspectRatio
  65. newOptions.maxHeight = height
  66. } else {
  67. newOptions.maxWidth = width
  68. newOptions.maxHeight = width / aspectRatio
  69. }
  70. return newOptions
  71. }
  72. // Canvas render method, allows to implement a different rendering algorithm:
  73. loadImage.renderImageToCanvas = function (
  74. canvas,
  75. img,
  76. sourceX,
  77. sourceY,
  78. sourceWidth,
  79. sourceHeight,
  80. destX,
  81. destY,
  82. destWidth,
  83. destHeight
  84. ) {
  85. canvas.getContext('2d').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 = img.getContext ||
  111. (loadImage.hasCanvasOption(options) && canvas.getContext)
  112. var width = img.naturalWidth || img.width
  113. var height = img.naturalHeight || img.height
  114. var destWidth = width
  115. var destHeight = height
  116. var maxWidth
  117. var maxHeight
  118. var minWidth
  119. var minHeight
  120. var sourceWidth
  121. var sourceHeight
  122. var sourceX
  123. var sourceY
  124. var pixelRatio
  125. var downsamplingRatio
  126. var tmp
  127. function scaleUp () {
  128. var scale = Math.max(
  129. (minWidth || destWidth) / destWidth,
  130. (minHeight || destHeight) / destHeight
  131. )
  132. if (scale > 1) {
  133. destWidth *= scale
  134. destHeight *= scale
  135. }
  136. }
  137. function scaleDown () {
  138. var scale = Math.min(
  139. (maxWidth || destWidth) / destWidth,
  140. (maxHeight || destHeight) / destHeight
  141. )
  142. if (scale < 1) {
  143. destWidth *= scale
  144. destHeight *= scale
  145. }
  146. }
  147. if (useCanvas) {
  148. options = loadImage.getTransformedOptions(img, options, data)
  149. sourceX = options.left || 0
  150. sourceY = options.top || 0
  151. if (options.sourceWidth) {
  152. sourceWidth = options.sourceWidth
  153. if (options.right !== undefined && options.left === undefined) {
  154. sourceX = width - sourceWidth - options.right
  155. }
  156. } else {
  157. sourceWidth = width - sourceX - (options.right || 0)
  158. }
  159. if (options.sourceHeight) {
  160. sourceHeight = options.sourceHeight
  161. if (options.bottom !== undefined && options.top === undefined) {
  162. sourceY = height - sourceHeight - options.bottom
  163. }
  164. } else {
  165. sourceHeight = height - sourceY - (options.bottom || 0)
  166. }
  167. destWidth = sourceWidth
  168. destHeight = sourceHeight
  169. }
  170. maxWidth = options.maxWidth
  171. maxHeight = options.maxHeight
  172. minWidth = options.minWidth
  173. minHeight = options.minHeight
  174. if (useCanvas && maxWidth && maxHeight && options.crop) {
  175. destWidth = maxWidth
  176. destHeight = maxHeight
  177. tmp = sourceWidth / sourceHeight - maxWidth / maxHeight
  178. if (tmp < 0) {
  179. sourceHeight = maxHeight * sourceWidth / maxWidth
  180. if (options.top === undefined && options.bottom === undefined) {
  181. sourceY = (height - sourceHeight) / 2
  182. }
  183. } else if (tmp > 0) {
  184. sourceWidth = maxWidth * sourceHeight / maxHeight
  185. if (options.left === undefined && options.right === undefined) {
  186. sourceX = (width - sourceWidth) / 2
  187. }
  188. }
  189. } else {
  190. if (options.contain || options.cover) {
  191. minWidth = maxWidth = maxWidth || minWidth
  192. minHeight = maxHeight = maxHeight || minHeight
  193. }
  194. if (options.cover) {
  195. scaleDown()
  196. scaleUp()
  197. } else {
  198. scaleUp()
  199. scaleDown()
  200. }
  201. }
  202. if (useCanvas) {
  203. pixelRatio = options.pixelRatio
  204. if (pixelRatio > 1) {
  205. canvas.style.width = destWidth + 'px'
  206. canvas.style.height = destHeight + 'px'
  207. destWidth *= pixelRatio
  208. destHeight *= pixelRatio
  209. canvas.getContext('2d').scale(pixelRatio, pixelRatio)
  210. }
  211. downsamplingRatio = options.downsamplingRatio
  212. if (downsamplingRatio > 0 && downsamplingRatio < 1 &&
  213. destWidth < sourceWidth && destHeight < sourceHeight) {
  214. while (sourceWidth * downsamplingRatio > destWidth) {
  215. canvas.width = sourceWidth * downsamplingRatio
  216. canvas.height = sourceHeight * downsamplingRatio
  217. loadImage.renderImageToCanvas(
  218. canvas,
  219. img,
  220. sourceX,
  221. sourceY,
  222. sourceWidth,
  223. sourceHeight,
  224. 0,
  225. 0,
  226. canvas.width,
  227. canvas.height
  228. )
  229. sourceX = 0
  230. sourceY = 0
  231. sourceWidth = canvas.width
  232. sourceHeight = canvas.height
  233. img = document.createElement('canvas')
  234. img.width = sourceWidth
  235. img.height = sourceHeight
  236. loadImage.renderImageToCanvas(
  237. img,
  238. canvas,
  239. 0,
  240. 0,
  241. sourceWidth,
  242. sourceHeight,
  243. 0,
  244. 0,
  245. sourceWidth,
  246. sourceHeight
  247. )
  248. }
  249. }
  250. canvas.width = destWidth
  251. canvas.height = destHeight
  252. loadImage.transformCoordinates(
  253. canvas,
  254. options
  255. )
  256. return loadImage.renderImageToCanvas(
  257. canvas,
  258. img,
  259. sourceX,
  260. sourceY,
  261. sourceWidth,
  262. sourceHeight,
  263. 0,
  264. 0,
  265. destWidth,
  266. destHeight
  267. )
  268. }
  269. img.width = destWidth
  270. img.height = destHeight
  271. return img
  272. }
  273. }))