You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

313 lines
10 KiB

1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
  1. Page({
  2. data: {
  3. // movable-view左上角相对于movable-area的坐标x,y,
  4. // 由于movable-area左上角位于屏幕原点,因此x,y也是movable-view相对于屏幕的坐标
  5. x: 0,
  6. y: 0,
  7. scale: 1, // 用来控制moveable-view的缩放比例,回撤重置时需要
  8. src: {
  9. // 图片的源文件数据
  10. path: '',
  11. orientation: 'up',
  12. // width和height在最初时和屏幕尺寸做比较,做一个合适的缩放
  13. // 在截图的时候,计算方框在源图片的位置也需要用到width和height
  14. width: 0,
  15. height: 0,
  16. ratio: 1, // 图片的长宽比,最开始需要根据ratio判断图片的形状是长图还是宽图,进行合适的居中放置
  17. },
  18. image: {
  19. // 最初图片在屏幕上显示的宽度和高度
  20. // 经过缩放后也是基于这两个尺寸计算新的尺寸
  21. initialWidth: 0,
  22. initialHeight: 0,
  23. // 控制最初图片在屏幕中的位置
  24. initialX: 0,
  25. initialY: 0,
  26. // 经过缩放移动后图片在屏幕中的位置
  27. // 截图时找方框在源图片中的位置,是基于屏幕坐标系,所以需要图片的当前位置
  28. curX: 0,
  29. curY: 0,
  30. // 图片当前的缩放比例,用于计算图片当前显示的尺寸大小
  31. curScale: 1
  32. },
  33. // 屏幕尺寸windowWidth和windowHeight
  34. windowWidth: 0,
  35. windowHeight: 0,
  36. cropBorder: {
  37. // 截图的方框相对于屏幕中的位置
  38. x: 0,
  39. y: 0,
  40. // 截图方框的尺寸
  41. size: 0
  42. },
  43. },
  44. /**
  45. * 生命周期函数--监听页面加载
  46. */
  47. onLoad: function(options) {
  48. this.takePhoto()
  49. },
  50. setImgInfo(options){
  51. let that = this;
  52. let _src = JSON.parse(options);
  53. _src.ratio = _src.height / _src.width;
  54. let systemInfo = wx.getSystemInfoSync();
  55. // 屏幕内框范围(这里定义左右边界30,上下边际50)
  56. // 但是因为movable-view能超出movable-area的范围太小,为了尽量放大图片的活动范围,这里取消了这个边界
  57. // let borderWidth = systemInfo.windowWidth - 2 * 30
  58. // let borderHeight = systemInfo.windowHeight - 2 * 50
  59. let _image = that.data.image
  60. if (_src.width > systemInfo.windowWidth && _src.height > systemInfo.windowHeight) {
  61. // 如果图片尺寸大于屏幕尺寸,需要缩放
  62. if (_src.ratio > 1) {
  63. // 如果是长图,按照宽度进行缩放
  64. _image.initialWidth = systemInfo.windowWidth
  65. // >> 0用来取整
  66. _image.initialHeight = (_src.ratio * systemInfo.windowWidth) >> 0
  67. } else {
  68. // 如果是宽图,按照高度进行缩放
  69. _image.initialWidth = systemInfo.windowHeight,
  70. _image.initialHeight = (systemInfo.windowHeight / _src.ratio) >> 0
  71. }
  72. } else {
  73. _image.initialWidth = _src.width
  74. _image.initialHeight = _src.height
  75. }
  76. // 控制图片在屏幕居中
  77. _image.initialX = 0//(systemInfo.windowWidth - _image.initialWidth) >> 1
  78. _image.initialY = 0//(systemInfo.windowHeight - _image.initialHeight) >> 1
  79. console.log(JSON.stringify(_image))
  80. // 定义方框的位置和尺寸
  81. let _cropBorder = {}
  82. _cropBorder.size = systemInfo.windowWidth * 0.8
  83. _cropBorder.x = (systemInfo.windowWidth - _cropBorder.size) >> 1
  84. _cropBorder.y = (systemInfo.windowHeight - _cropBorder.size) >> 1
  85. that.setData({
  86. src: _src,
  87. image: _image,
  88. cropBorder: _cropBorder,
  89. windowWidth: systemInfo.windowWidth,
  90. windowHeight: systemInfo.windowHeight
  91. })
  92. setTimeout(()=>{
  93. that.drawFrame()
  94. },500)
  95. },
  96. /**
  97. * 移动movable-view的回调
  98. */
  99. onChange(e) {
  100. console.log(e.detail)
  101. let that = this;
  102. that.setData({
  103. 'image.curX': e.detail.x,
  104. 'image.curY': e.detail.y
  105. })
  106. },
  107. /**
  108. * 缩放moveable-view的回调
  109. */
  110. onScale(e) {
  111. console.log(e.detail)
  112. let that = this;
  113. that.setData({
  114. 'image.curX': e.detail.x,
  115. 'image.curY': e.detail.y,
  116. 'image.curScale': e.detail.scale
  117. })
  118. },
  119. // 拍照
  120. takePhoto() {
  121. var that=this,
  122. width = that.data.screenW,
  123. height = that.data.screenW;
  124. wx.chooseImage({
  125. count:1,
  126. sizeType: ['original', 'compressed'],
  127. sourceType: ['album', 'camera'],
  128. success:function(res){
  129. const tempFilePaths = res.tempFilePaths[0];
  130. wx.getImageInfo({
  131. src: tempFilePaths,
  132. success: function(msg) {
  133. let data = JSON.stringify(msg)
  134. that.setImgInfo(data)
  135. }
  136. })
  137. },
  138. fail:function(error){
  139. console.error("调用本地相册文件时出错")
  140. console.warn(error)
  141. },
  142. // // 确定提交图片
  143. // complete:function(back){
  144. // console.log(back)
  145. // }
  146. })
  147. },
  148. // 绘制方框
  149. drawFrame(){
  150. let that = this;
  151. let cropBorder = that.data.cropBorder
  152. console.log(cropBorder,"cropBorder")
  153. this.context = wx.createCanvasContext('myCanvas')
  154. // 设置背景黑色透明度0.5,不要使用opacity,会导致后期截出来的图片也是半透明
  155. this.context.setFillStyle('rgba(0,0,0,0.5)')
  156. this.context.fillRect(0, 0, that.data.windowWidth, that.data.windowHeight)
  157. // 挖出来一个方框,这个方框区域就是全透明了
  158. this.context.clearRect(cropBorder.x, cropBorder.y, cropBorder.size, cropBorder.size * (4/3))
  159. // 画方框的外框
  160. this.context.setStrokeStyle('white')
  161. // 往外画大一圈,这样在canvas上填充图片的时候框线就不会变细啦
  162. this.context.strokeRect(cropBorder.x - 1, cropBorder.y - 1, cropBorder.size + 2, (cropBorder.size * (4/3)) + 2)
  163. this.context.draw()
  164. },
  165. /**
  166. * 生命周期函数--监听页面初次渲染完成
  167. */
  168. onReady: function() {
  169. // let that = this;
  170. // let cropBorder = that.data.cropBorder
  171. // this.context = wx.createCanvasContext('myCanvas')
  172. // // 设置背景黑色透明度0.5,不要使用opacity,会导致后期截出来的图片也是半透明
  173. // this.context.setFillStyle('rgba(0,0,0,0.5)')
  174. // this.context.fillRect(0, 0, that.data.windowWidth, that.data.windowHeight)
  175. // // 挖出来一个方框,这个方框区域就是全透明了
  176. // this.context.clearRect(cropBorder.x, cropBorder.y, cropBorder.size, cropBorder.size)
  177. // // 画方框的外框
  178. // this.context.setStrokeStyle('white')
  179. // // 往外画大一圈,这样在canvas上填充图片的时候框线就不会变细啦
  180. // this.context.strokeRect(cropBorder.x - 1, cropBorder.y - 1, cropBorder.size + 2, cropBorder.size + 2)
  181. // this.context.draw()
  182. },
  183. /**
  184. * 取消截图
  185. */
  186. cancel(event) {
  187. wx.navigateBack()
  188. },
  189. /**
  190. * 回撤这地方有个问题
  191. * 本来是想图片一次性移动和缩放回到最初的位置和大小但是发现点击第一次只能实现图片移动到初始点
  192. * 点击第二次才是缩放到初始大小
  193. * 后来发现小程序移动有一个过程会不停地回调onChange()
  194. * 如果一定要实现只能是当onChange中xy归0之后再控制缩放
  195. * 但是x和y是浮点数零判断不精确而且影响性能所以放弃了
  196. */
  197. reset(event) {
  198. let that = this;
  199. that.setData({
  200. scale: 1,
  201. x: 0,
  202. y: 0,
  203. })
  204. },
  205. /**
  206. * 点击完成的回调
  207. * 完成截图回传图片到上一页
  208. */
  209. complete(event) {
  210. let that = this
  211. let src = that.data.src
  212. console.log(src)
  213. let cropBorder = this.data.cropBorder
  214. let image = that.data.image
  215. // 当前图片显示的大小
  216. let curImageWidth = image.initialWidth * image.curScale
  217. let curImageHeight = image.initialHeight * image.curScale
  218. // 将方框位置换算到源图片中的位置srcX,srcY
  219. let srcX = (cropBorder.x - image.curX) / curImageWidth * src.width
  220. // canvas的height是100%,而bottom是120rpx,因此canvas的位置不是在原点,需要减去这个120rpx
  221. // 置于这里为什么要有个120,因为底部栏也是透明的,但字是亮的,我想呈现底部栏在上方不被遮罩挡住的效果
  222. let srcY = (cropBorder.y - image.curY - 120 / 750 * that.data.windowWidth) / curImageHeight * src.height
  223. // 方框区域映射到源图片中的尺寸
  224. let srcWidth = cropBorder.size / curImageWidth * src.width
  225. let srcHeight = (cropBorder.size * (4/3)) / curImageHeight * src.height
  226. console.log('srcX = ' + srcX + ', srcY = ' + srcY + ', srcWidth = ' + srcWidth + ', srcHeight = ' + srcHeight + ', cropX = ' + cropBorder.x + ', cropY = ' + cropBorder.y + ', cropSize = ' + cropBorder.size)
  227. // 绘制图片不要透明啦,不然会看到重影
  228. this.context.setFillStyle('rgba(0,0,0,1)')
  229. // 鉴于尺寸的精确度,方框内图片的覆盖在y方向会有微微的偏移,
  230. // 但是一旦截图就返回上一页了,强迫症患者没有后悔的余地。
  231. this.context.drawImage(src.path, srcX, srcY, srcWidth, srcHeight, cropBorder.x, cropBorder.y, cropBorder.size, cropBorder.size)
  232. // 这里绘图一定要有回调,不然图片还没绘制完成就截图那就GG了
  233. this.context.draw(true, function(res) {
  234. wx.canvasToTempFilePath({
  235. canvasId: 'myCanvas',
  236. x: cropBorder.x,
  237. y: cropBorder.y,
  238. width: cropBorder.size,
  239. height: cropBorder.size,
  240. destWidth: cropBorder.size,
  241. destHeight: cropBorder.size,
  242. fileType: 'jpg',
  243. success: function(data) {
  244. console.log(data)
  245. // 将图片回传到上一页
  246. var pages = getCurrentPages();
  247. if (pages.length > 1) {
  248. var prePage = pages[pages.length - 2];
  249. var facepicture = wx.getFileSystemManager().readFileSync(data.tempFilePath, "base64")
  250. prePage.setData({
  251. avatarPath: data.tempFilePath,
  252. chooseface: true,
  253. facepic: `${facepicture}`
  254. })
  255. }
  256. wx.navigateBack()
  257. },
  258. fail: function(err) {
  259. console.log(err)
  260. }
  261. })
  262. })
  263. },
  264. /**
  265. * 生命周期函数--监听页面显示
  266. */
  267. onShow: function() {
  268. },
  269. /**
  270. * 生命周期函数--监听页面隐藏
  271. */
  272. onHide: function() {
  273. },
  274. /**
  275. * 生命周期函数--监听页面卸载
  276. */
  277. onUnload: function() {
  278. },
  279. /**
  280. * 页面相关事件处理函数--监听用户下拉动作
  281. */
  282. onPullDownRefresh: function() {
  283. },
  284. /**
  285. * 页面上拉触底事件的处理函数
  286. */
  287. onReachBottom: function() {
  288. },
  289. /**
  290. * 用户点击右上角分享
  291. */
  292. onShareAppMessage: function() {
  293. }
  294. })