load-image.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. /*
  2. * JavaScript Load Image
  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. * http://www.opensource.org/licenses/MIT
  10. */
  11. /*global define, module, window, document, URL, webkitURL, FileReader */
  12. ;(function ($) {
  13. 'use strict'
  14. // Loads an image for a given File object.
  15. // Invokes the callback with an img or optional canvas
  16. // element (if supported by the browser) as parameter:
  17. var loadImage = function (file, callback, options) {
  18. var img = document.createElement('img')
  19. var url
  20. var oUrl
  21. img.onerror = callback
  22. img.onload = function () {
  23. if (oUrl && !(options && options.noRevoke)) {
  24. loadImage.revokeObjectURL(oUrl)
  25. }
  26. if (callback) {
  27. callback(loadImage.scale(img, options))
  28. }
  29. }
  30. if (loadImage.isInstanceOf('Blob', file) ||
  31. // Files are also Blob instances, but some browsers
  32. // (Firefox 3.6) support the File API but not Blobs:
  33. loadImage.isInstanceOf('File', file)) {
  34. url = oUrl = loadImage.createObjectURL(file)
  35. // Store the file type for resize processing:
  36. img._type = file.type
  37. } else if (typeof file === 'string') {
  38. url = file
  39. if (options && options.crossOrigin) {
  40. img.crossOrigin = options.crossOrigin
  41. }
  42. } else {
  43. return false
  44. }
  45. if (url) {
  46. img.src = url
  47. return img
  48. }
  49. return loadImage.readFile(file, function (e) {
  50. var target = e.target
  51. if (target && target.result) {
  52. img.src = target.result
  53. } else {
  54. if (callback) {
  55. callback(e)
  56. }
  57. }
  58. })
  59. }
  60. // The check for URL.revokeObjectURL fixes an issue with Opera 12,
  61. // which provides URL.createObjectURL but doesn't properly implement it:
  62. var urlAPI = (window.createObjectURL && window) ||
  63. (window.URL && URL.revokeObjectURL && URL) ||
  64. (window.webkitURL && webkitURL)
  65. loadImage.isInstanceOf = function (type, obj) {
  66. // Cross-frame instanceof check
  67. return Object.prototype.toString.call(obj) === '[object ' + type + ']'
  68. }
  69. // Transform image coordinates, allows to override e.g.
  70. // the canvas orientation based on the orientation option,
  71. // gets canvas, options passed as arguments:
  72. loadImage.transformCoordinates = function () {
  73. return
  74. }
  75. // Returns transformed options, allows to override e.g.
  76. // maxWidth, maxHeight and crop options based on the aspectRatio.
  77. // gets img, options passed as arguments:
  78. loadImage.getTransformedOptions = function (img, options) {
  79. var aspectRatio = options.aspectRatio
  80. var newOptions
  81. var i
  82. var width
  83. var height
  84. if (!aspectRatio) {
  85. return options
  86. }
  87. newOptions = {}
  88. for (i in options) {
  89. if (options.hasOwnProperty(i)) {
  90. newOptions[i] = options[i]
  91. }
  92. }
  93. newOptions.crop = true
  94. width = img.naturalWidth || img.width
  95. height = img.naturalHeight || img.height
  96. if (width / height > aspectRatio) {
  97. newOptions.maxWidth = height * aspectRatio
  98. newOptions.maxHeight = height
  99. } else {
  100. newOptions.maxWidth = width
  101. newOptions.maxHeight = width / aspectRatio
  102. }
  103. return newOptions
  104. }
  105. // Canvas render method, allows to implement a different rendering algorithm:
  106. loadImage.renderImageToCanvas = function (
  107. canvas,
  108. img,
  109. sourceX,
  110. sourceY,
  111. sourceWidth,
  112. sourceHeight,
  113. destX,
  114. destY,
  115. destWidth,
  116. destHeight
  117. ) {
  118. canvas.getContext('2d').drawImage(
  119. img,
  120. sourceX,
  121. sourceY,
  122. sourceWidth,
  123. sourceHeight,
  124. destX,
  125. destY,
  126. destWidth,
  127. destHeight
  128. )
  129. return canvas
  130. }
  131. // This method is used to determine if the target image
  132. // should be a canvas element:
  133. loadImage.hasCanvasOption = function (options) {
  134. return options.canvas || options.crop || !!options.aspectRatio
  135. }
  136. // Scales and/or crops the given image (img or canvas HTML element)
  137. // using the given options.
  138. // Returns a canvas object if the browser supports canvas
  139. // and the hasCanvasOption method returns true or a canvas
  140. // object is passed as image, else the scaled image:
  141. loadImage.scale = function (img, options) {
  142. options = options || {}
  143. var canvas = document.createElement('canvas')
  144. var useCanvas = img.getContext ||
  145. (loadImage.hasCanvasOption(options) && canvas.getContext)
  146. var width = img.naturalWidth || img.width
  147. var height = img.naturalHeight || img.height
  148. var destWidth = width
  149. var destHeight = height
  150. var maxWidth
  151. var maxHeight
  152. var minWidth
  153. var minHeight
  154. var sourceWidth
  155. var sourceHeight
  156. var sourceX
  157. var sourceY
  158. var pixelRatio
  159. var downsamplingRatio
  160. var tmp
  161. function scaleUp () {
  162. var scale = Math.max(
  163. (minWidth || destWidth) / destWidth,
  164. (minHeight || destHeight) / destHeight
  165. )
  166. if (scale > 1) {
  167. destWidth *= scale
  168. destHeight *= scale
  169. }
  170. }
  171. function scaleDown () {
  172. var scale = Math.min(
  173. (maxWidth || destWidth) / destWidth,
  174. (maxHeight || destHeight) / destHeight
  175. )
  176. if (scale < 1) {
  177. destWidth *= scale
  178. destHeight *= scale
  179. }
  180. }
  181. if (useCanvas) {
  182. options = loadImage.getTransformedOptions(img, options)
  183. sourceX = options.left || 0
  184. sourceY = options.top || 0
  185. if (options.sourceWidth) {
  186. sourceWidth = options.sourceWidth
  187. if (options.right !== undefined && options.left === undefined) {
  188. sourceX = width - sourceWidth - options.right
  189. }
  190. } else {
  191. sourceWidth = width - sourceX - (options.right || 0)
  192. }
  193. if (options.sourceHeight) {
  194. sourceHeight = options.sourceHeight
  195. if (options.bottom !== undefined && options.top === undefined) {
  196. sourceY = height - sourceHeight - options.bottom
  197. }
  198. } else {
  199. sourceHeight = height - sourceY - (options.bottom || 0)
  200. }
  201. destWidth = sourceWidth
  202. destHeight = sourceHeight
  203. }
  204. maxWidth = options.maxWidth
  205. maxHeight = options.maxHeight
  206. minWidth = options.minWidth
  207. minHeight = options.minHeight
  208. if (useCanvas && maxWidth && maxHeight && options.crop) {
  209. destWidth = maxWidth
  210. destHeight = maxHeight
  211. tmp = sourceWidth / sourceHeight - maxWidth / maxHeight
  212. if (tmp < 0) {
  213. sourceHeight = maxHeight * sourceWidth / maxWidth
  214. if (options.top === undefined && options.bottom === undefined) {
  215. sourceY = (height - sourceHeight) / 2
  216. }
  217. } else if (tmp > 0) {
  218. sourceWidth = maxWidth * sourceHeight / maxHeight
  219. if (options.left === undefined && options.right === undefined) {
  220. sourceX = (width - sourceWidth) / 2
  221. }
  222. }
  223. } else {
  224. if (options.contain || options.cover) {
  225. minWidth = maxWidth = maxWidth || minWidth
  226. minHeight = maxHeight = maxHeight || minHeight
  227. }
  228. if (options.cover) {
  229. scaleDown()
  230. scaleUp()
  231. } else {
  232. scaleUp()
  233. scaleDown()
  234. }
  235. }
  236. if (useCanvas) {
  237. pixelRatio = options.pixelRatio
  238. if (pixelRatio > 1) {
  239. canvas.style.width = destWidth + 'px'
  240. canvas.style.height = destHeight + 'px'
  241. destWidth *= pixelRatio
  242. destHeight *= pixelRatio
  243. canvas.getContext('2d').scale(pixelRatio, pixelRatio)
  244. }
  245. downsamplingRatio = options.downsamplingRatio
  246. if (downsamplingRatio > 0 && downsamplingRatio < 1 &&
  247. destWidth < sourceWidth && destHeight < sourceHeight) {
  248. while (sourceWidth * downsamplingRatio > destWidth) {
  249. canvas.width = sourceWidth * downsamplingRatio
  250. canvas.height = sourceHeight * downsamplingRatio
  251. loadImage.renderImageToCanvas(
  252. canvas,
  253. img,
  254. sourceX,
  255. sourceY,
  256. sourceWidth,
  257. sourceHeight,
  258. 0,
  259. 0,
  260. canvas.width,
  261. canvas.height
  262. )
  263. sourceWidth = canvas.width
  264. sourceHeight = canvas.height
  265. img = document.createElement('canvas')
  266. img.width = sourceWidth
  267. img.height = sourceHeight
  268. loadImage.renderImageToCanvas(
  269. img,
  270. canvas,
  271. 0,
  272. 0,
  273. sourceWidth,
  274. sourceHeight,
  275. 0,
  276. 0,
  277. sourceWidth,
  278. sourceHeight
  279. )
  280. }
  281. }
  282. canvas.width = destWidth
  283. canvas.height = destHeight
  284. loadImage.transformCoordinates(
  285. canvas,
  286. options
  287. )
  288. return loadImage.renderImageToCanvas(
  289. canvas,
  290. img,
  291. sourceX,
  292. sourceY,
  293. sourceWidth,
  294. sourceHeight,
  295. 0,
  296. 0,
  297. destWidth,
  298. destHeight
  299. )
  300. }
  301. img.width = destWidth
  302. img.height = destHeight
  303. return img
  304. }
  305. loadImage.createObjectURL = function (file) {
  306. return urlAPI ? urlAPI.createObjectURL(file) : false
  307. }
  308. loadImage.revokeObjectURL = function (url) {
  309. return urlAPI ? urlAPI.revokeObjectURL(url) : false
  310. }
  311. // Loads a given File object via FileReader interface,
  312. // invokes the callback with the event object (load or error).
  313. // The result can be read via event.target.result:
  314. loadImage.readFile = function (file, callback, method) {
  315. if (window.FileReader) {
  316. var fileReader = new FileReader()
  317. fileReader.onload = fileReader.onerror = callback
  318. method = method || 'readAsDataURL'
  319. if (fileReader[method]) {
  320. fileReader[method](file)
  321. return fileReader
  322. }
  323. }
  324. return false
  325. }
  326. if (typeof define === 'function' && define.amd) {
  327. define(function () {
  328. return loadImage
  329. })
  330. } else if (typeof module === 'object' && module.exports) {
  331. module.exports = loadImage
  332. } else {
  333. $.loadImage = loadImage
  334. }
  335. }(window))