image-picker.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. // 上传前压缩:小程序默认上传超时 60 秒,手机原图/聊天记录图片较大时容易超时中断。
  2. // 超过 800KB 的图片先用 compressImage 压到约 75% 质量,失败则回退原图。
  3. var COMPRESS_THRESHOLD = 800 * 1024
  4. export function compressPickedImages(paths, files, callback) {
  5. var result = []
  6. var index = 0
  7. function finish() {
  8. callback(result)
  9. }
  10. function next() {
  11. if (index >= paths.length) {
  12. finish()
  13. return
  14. }
  15. var i = index++
  16. var path = paths[i]
  17. var file = files && files[i]
  18. var size = file && typeof file.size === 'number' ? file.size : 0
  19. if (!path || (size > 0 && size <= COMPRESS_THRESHOLD)
  20. || typeof uni === 'undefined' || typeof uni.compressImage !== 'function') {
  21. result[i] = path
  22. next()
  23. return
  24. }
  25. uni.compressImage({
  26. src: path,
  27. quality: 75,
  28. success: function (res) {
  29. result[i] = (res && res.tempFilePath) || path
  30. next()
  31. },
  32. fail: function () {
  33. result[i] = path
  34. next()
  35. }
  36. })
  37. }
  38. if (!paths || !paths.length) {
  39. callback([])
  40. return
  41. }
  42. next()
  43. }
  44. /**
  45. * 统一图片选择器(微信小程序支持「从聊天记录选择图片」)
  46. *
  47. * 背景:
  48. * uni.chooseImage 只能从 album(手机相册)或 camera(拍照)选图,
  49. * 无法直接选择聊天记录里的图片;微信小程序要从聊天记录选图,
  50. * 必须调用 uni.chooseMessageFile({ type: 'image' })。
  51. * 为保证小程序端所有图片上传入口都能从聊天记录选图,统一使用本方法。
  52. *
  53. * 用法与 uni.chooseImage 基本一致(回调风格):
  54. * pickImage({
  55. * count: 1,
  56. * sizeType: ['compressed'],
  57. * sourceType: ['album', 'camera'], // 可选,默认 ['album', 'camera']
  58. * success: function (res) {
  59. * // res.tempFilePaths: 图片本地临时路径数组
  60. * // res.tempFiles: [{ path, size, name, type }]
  61. * },
  62. * fail: function (err) {}
  63. * })
  64. *
  65. * 说明:
  66. * 微信小程序下会先弹出 ActionSheet:拍照 / 从相册选择 / 从聊天记录选择,
  67. * 前两项走 uni.chooseImage,最后一项走 uni.chooseMessageFile。
  68. * 非微信平台(H5/App 等)不支持聊天记录选图,保持原 uni.chooseImage 行为。
  69. */
  70. export function pickImage(options) {
  71. var opts = options || {}
  72. var count = opts.count || 9
  73. var sizeType = opts.sizeType || ['original', 'compressed']
  74. var sourceType = opts.sourceType || ['album', 'camera']
  75. var success = opts.success
  76. var fail = opts.fail
  77. var complete = opts.complete
  78. function finish(res) {
  79. if (success) success(res)
  80. if (complete) complete(res)
  81. }
  82. function onSuccess(res) {
  83. var paths = (res && res.tempFilePaths) || []
  84. if (!paths.length) {
  85. finish(res)
  86. return
  87. }
  88. compressPickedImages(paths, (res && res.tempFiles) || [], function (compressedPaths) {
  89. var out = {}
  90. for (var key in res) {
  91. if (Object.prototype.hasOwnProperty.call(res, key)) out[key] = res[key]
  92. }
  93. out.tempFilePaths = compressedPaths
  94. if (res && res.tempFiles) {
  95. var files = []
  96. for (var i = 0; i < res.tempFiles.length; i++) {
  97. var file = res.tempFiles[i] || {}
  98. var copy = {}
  99. for (var k in file) {
  100. if (Object.prototype.hasOwnProperty.call(file, k)) copy[k] = file[k]
  101. }
  102. copy.path = compressedPaths[i] || copy.path
  103. files.push(copy)
  104. }
  105. out.tempFiles = files
  106. }
  107. finish(out)
  108. })
  109. }
  110. function onFail(err) {
  111. if (fail) fail(err)
  112. if (complete) complete(err)
  113. }
  114. // sourceType 只支持单个来源时(如 ['camera'])直接调起对应入口
  115. function callChooseImage(types) {
  116. uni.chooseImage({
  117. count: count,
  118. sizeType: sizeType,
  119. sourceType: types,
  120. success: onSuccess,
  121. fail: onFail
  122. })
  123. }
  124. // #ifdef MP-WEIXIN
  125. // 微信小程序:先选来源,再从聊天记录 / 相册 / 相机取图
  126. var actionList = []
  127. if (sourceType.indexOf('camera') > -1) actionList.push({ label: '拍照', type: 'camera' })
  128. if (sourceType.indexOf('album') > -1) actionList.push({ label: '从相册选择', type: 'album' })
  129. actionList.push({ label: '从聊天记录选择', type: 'chat' })
  130. var itemList = []
  131. for (var i = 0; i < actionList.length; i++) itemList.push(actionList[i].label)
  132. uni.showActionSheet({
  133. itemList: itemList,
  134. success: function (sheetRes) {
  135. var action = actionList[sheetRes.tapIndex]
  136. if (!action) return
  137. if (action.type !== 'chat') {
  138. callChooseImage([action.type])
  139. return
  140. }
  141. if (typeof uni.chooseMessageFile !== 'function') {
  142. // 低版本基础库不支持聊天记录选图,降级为相册选图
  143. callChooseImage(['album'])
  144. return
  145. }
  146. uni.chooseMessageFile({
  147. count: count,
  148. type: 'image',
  149. success: function (res) {
  150. var files = []
  151. var tempFiles = res.tempFiles || []
  152. for (var j = 0; j < tempFiles.length; j++) {
  153. files.push({
  154. path: tempFiles[j].path,
  155. size: tempFiles[j].size,
  156. name: tempFiles[j].name,
  157. type: tempFiles[j].type
  158. })
  159. }
  160. var paths = []
  161. for (var k = 0; k < files.length; k++) paths.push(files[k].path)
  162. onSuccess({ tempFilePaths: paths, tempFiles: files })
  163. },
  164. fail: onFail
  165. })
  166. },
  167. fail: onFail
  168. })
  169. // #endif
  170. // #ifndef MP-WEIXIN
  171. // 非微信平台不支持聊天记录选图,保持原行为
  172. callChooseImage(sourceType)
  173. // #endif
  174. }