canvaspopup.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. <!-- 分享图片弹框 -->
  2. <template>
  3. <!-- 普通弹窗 -->
  4. <uni-popup ref="canvaspopup" >
  5. <view class="canvaspopup-content">
  6. <canvas class="drawimg-canvas" id="drawimg" type="2d" :style="{width:width+'px',height: height+'px'}"></canvas>
  7. <template v-if="poster">
  8. <!-- <label for="btnId_1234" style="z-index:99;"> -->
  9. <img :src="poster" mode="widthFix" class="poster-img" :show-menu-by-longpress="true" alt="" @click="showShareSheet">
  10. <!-- </label> -->
  11. <!-- <view class="footer">
  12. <button type="default" id="btnId_1234" class="btn" open-type="share">转发</button>
  13. <button type="default" class="btn" @click="handleSaveImg">保存</button>
  14. </view> -->
  15. </template>
  16. <template v-else>
  17. <view class="empty">
  18. 海报生成中
  19. <image src="/static/ai/loading.gif" style="margin-left: 8rpx;height: 10rpx; width: 50rpx;" alt="" srcset="">
  20. </view>
  21. </template>
  22. </view>
  23. </uni-popup>
  24. </template>
  25. <script>
  26. import { dateFormat } from '@/common/util.js'
  27. import { getQrcode } from '@/api/index.js'
  28. import {
  29. mapState,
  30. mapGetters,
  31. mapMutations
  32. } from 'vuex'
  33. var app = getApp();
  34. export default {
  35. props: {
  36. imgsrc: {
  37. type: String,
  38. default: ''
  39. },
  40. message: {
  41. type: String,
  42. default: ''
  43. }
  44. },
  45. data() {
  46. return {
  47. systemInfo: null,
  48. width: 0,
  49. height: 0,
  50. canvasAttrs: null,
  51. poster: '',
  52. netqrcode: 'https://api.aibaidu.com.cn/image/20230318_2c1b8aa247524edfa9ac7fb056f4814d.jpg',
  53. qrcode: ''
  54. };
  55. },
  56. computed: {
  57. ...mapState(['userId', 'settings', 'chatType'])
  58. },
  59. created() {
  60. console.log('app.globalData.systemInfo', app.globalData.systemInfo)
  61. this.systemInfo = app.globalData.systemInfo
  62. this.width = 256 * this.systemInfo.pixelRatio
  63. this.height = 320 * this.systemInfo.pixelRatio
  64. },
  65. mounted() {
  66. },
  67. methods: {
  68. dateFormat,
  69. async getQrcode() {
  70. const data = {
  71. page: "pages/ai/main/main",
  72. scene: `uid=${this.userId}&ctype=DRAW`,
  73. check_path: true,
  74. env_version: "release", //"release",体验版为 "trial",开发版为 "develop"
  75. width: 420,
  76. auto_color: false,
  77. line_color: {
  78. r: 5,
  79. g: 5,
  80. b: 5
  81. },
  82. is_hyaline: false
  83. }
  84. const res = await getQrcode(data)
  85. this.qrcode = "data:image/png;base64," + res.data
  86. this.drawCanvas()
  87. },
  88. getQrCodeImg() {
  89. // const src = this.settings.qrcode
  90. const that = this
  91. let fileName = new Date().valueOf();
  92. wx.downloadFile({ //下载图片到本地
  93. url: that.netqrcode,
  94. filePath: wx.env.USER_DATA_PATH + '/' + fileName + '.png',
  95. success(res) {
  96. if (res.statusCode === 200) {
  97. that.qrcode = res.filePath
  98. console.log("Drawing2:", new Date().getTime() % 10000);
  99. that.drawCanvas()
  100. }
  101. },
  102. fail() {
  103. }
  104. })
  105. },
  106. showPopup() {
  107. this.$refs.canvaspopup.open('center');
  108. this.poster = ''
  109. console.log("Drawing1:", new Date().getTime() % 10000);
  110. // this.startDownLoadImg()
  111. // this.drawCanvas()
  112. this.getQrcode()
  113. },
  114. // 先下载二维码
  115. startDownLoadImg() {
  116. this.getQrCodeImg()
  117. },
  118. startQueryElement() {
  119. // this.$nextTick(() => {
  120. var query = uni.createSelectorQuery().in(this);
  121. query.select('#drawimg').boundingClientRect().exec((res) => {
  122. // 返回值包括画布的实际宽高
  123. console.log(res)
  124. this.drawCanvas(res[0])
  125. })
  126. // })
  127. },
  128. drawCanvas() {
  129. const that = this
  130. // let ctx = wx.createCanvasContext('drawimg', this)
  131. const dpr = this.systemInfo.pixelRatio
  132. const query = uni.createSelectorQuery().in(this)
  133. query.select('#drawimg')
  134. .fields({ node: true, size: true })
  135. .exec(async (res) => {
  136. console.log("Drawing3:", new Date().getTime() % 10000);
  137. console.log(res)
  138. const canvas = res[0].node
  139. const ctx = canvas.getContext('2d')
  140. // const dpr = wx.getSystemInfoSync().pixelRatio
  141. canvas.width = res[0].width * dpr
  142. canvas.height = res[0].height * dpr
  143. ctx.scale(dpr, dpr)
  144. // ctx.scale(dpr, dpr)
  145. let canvasW = res[0].width // 画布的真实宽度
  146. let canvasH = res[0].height //画布的真实高度
  147. // 头像和二维码大小都需要在规定大小的基础上放大像素比的比例后面都会 *this.systemInfo.pixelRatio
  148. // let headerW = 48 * this.systemInfo.pixelRatio
  149. // let headerX = (canvasW - headerW) / 2
  150. // let headerY = 40 * this.systemInfo.pixelRatio
  151. // let qrcodeW = 73 * this.systemInfo.pixelRatio
  152. // let qrcodeX = 216 * this.systemInfo.pixelRatio
  153. // let qrcodeY = 400 * this.systemInfo.pixelRatio
  154. // 填充背景
  155. ctx.fillStyle = '#FFFFFF'
  156. ctx.fillRect(0, 0, canvasW, canvasH)
  157. ctx.save()
  158. // 画图
  159. const mainImg = canvas.createImage();
  160. mainImg.src = that.imgsrc;
  161. let mainImgPo = await new Promise((resolve, reject) => {
  162. mainImg.onload = () => {
  163. resolve(mainImg)
  164. }
  165. mainImg.onerror = (e) => {
  166. reject(e)
  167. }
  168. });
  169. let h = mainImgPo.height;
  170. let w = mainImgPo.width;
  171. const space = 10
  172. ctx.drawImage(mainImgPo, space * dpr, space * dpr, canvasW - space * dpr * 2, canvasW - space * dpr * 2)
  173. ctx.save()
  174. console.log("Drawing4 img1:", new Date().getTime() % 10000);
  175. // 画二维码
  176. const qrcodeImg = canvas.createImage();
  177. qrcodeImg.src = that.qrcode;
  178. let qrcodeImgPo = await new Promise((resolve, reject) => {
  179. qrcodeImg.onload = () => {
  180. resolve(qrcodeImg)
  181. }
  182. qrcodeImg.onerror = (e) => {
  183. reject(e)
  184. }
  185. });
  186. ctx.drawImage(qrcodeImgPo, canvasW - (space + 50) * dpr, canvasW + 4 * dpr, 50 * dpr, 50 * dpr)
  187. ctx.save()
  188. console.log("Drawing4 img2:", new Date().getTime() % 10000);
  189. //问题文案内容
  190. const msg = this.message.length > 13 ? this.message.substr(0, 13) + '...' : this.message
  191. ctx.textBaseline = 'top';
  192. ctx.textAlign = 'left';
  193. ctx.font = `${12 * dpr}px bold`; //设置字体大小,默认10
  194. ctx.fillStyle = '#333333'; //文字颜色:默认黑色
  195. ctx.fillText(msg, space * dpr , canvasW + 12 * dpr)//绘制文本
  196. ctx.save()
  197. // //文案内容
  198. // ctx.textBaseline = "bottom";
  199. // ctx.textAlign = 'left';
  200. // ctx.font = `${12 * dpr}px bold`; //设置字体大小,默认10
  201. // ctx.fillStyle = '#333333'; //文字颜色:默认黑色
  202. // ctx.fillText('AI降临派', space * dpr , canvasW + 32 * dpr)//绘制文本
  203. // ctx.save()
  204. ctx.font = `${10 * dpr}px bold`; //设置字体大小,默认10
  205. // ctx.fillStyle = '#333333'; //文字颜色:默认黑色
  206. ctx.fillText('长按识别体验AI绘画', space * dpr, canvasW + 36 * dpr)//绘制文本
  207. ctx.save()
  208. console.log("Drawing4 over:", new Date().getTime() % 10000);
  209. setTimeout(() => {
  210. wx.canvasToTempFilePath({
  211. canvas: canvas,
  212. success: (res) => {
  213. console.log("Drawing5 canvasToTempFilePath:", new Date().getTime() % 10000);
  214. console.log('canvasToTempFilePath', res);
  215. that.poster = res.tempFilePath
  216. that.showShareSheet()
  217. },
  218. fail(res) {
  219. console.log('canvasToTempFilePath FAIL:', res);
  220. }
  221. })
  222. }, 200)
  223. })
  224. },
  225. showShareSheet() {
  226. const that = this
  227. wx.showShareImageMenu({
  228. path: this.poster,
  229. success: (res) => {
  230. console.log('showShareImageMenu success');
  231. that.$refs.canvaspopup.close();
  232. },
  233. fail() {
  234. console.log('showShareImageMenu fail');
  235. that.$refs.canvaspopup.close();
  236. }
  237. })
  238. },
  239. handleSaveImg() {
  240. const that = this
  241. wx.saveImageToPhotosAlbum({
  242. filePath: that.poster,
  243. success: function (data) {
  244. wx.showToast({
  245. title: '已保存到相册',
  246. icon: 'success',
  247. duration: 2000
  248. })
  249. },
  250. fail: function (err) {
  251. console.log(err)
  252. },
  253. complete(res) {
  254. console.log(res);
  255. }
  256. })
  257. },
  258. async handleSaveImg2() {
  259. let self = this;
  260. const query = wx.createSelectorQuery();
  261. const canvasObj = await new Promise((resolve, reject) => {
  262. query.select('#posterCanvas')
  263. .fields({ node: true, size: true })
  264. .exec(async (res) => {
  265. resolve(res[0].node);
  266. })
  267. });
  268. console.log(canvasObj);
  269. wx.canvasToTempFilePath({
  270. //fileType: 'jpg',
  271. //canvasId: 'posterCanvas', //之前的写法
  272. canvas: canvasObj, //现在的写法
  273. success: (res) => {
  274. console.log(res);
  275. //保存图片
  276. wx.saveImageToPhotosAlbum({
  277. filePath: res.tempFilePath,
  278. success: function (data) {
  279. wx.showToast({
  280. title: '已保存到相册',
  281. icon: 'success',
  282. duration: 2000
  283. })
  284. },
  285. fail: function (err) {
  286. console.log(err);
  287. if (err.errMsg === "saveImageToPhotosAlbum:fail auth deny") {
  288. console.log("当初用户拒绝,再次发起授权")
  289. }
  290. self.$refs.canvaspopup.close();
  291. },
  292. complete(res) {
  293. wx.hideLoading();
  294. console.log(res);
  295. }
  296. })
  297. },
  298. fail(res) {
  299. console.log(res);
  300. }
  301. }, this)
  302. },
  303. getPhotosAuthorize: function () {
  304. let self = this;
  305. wx.getSetting({
  306. success(res) {
  307. console.log(res)
  308. if (!res.authSetting['scope.writePhotosAlbum']) {
  309. wx.authorize({
  310. scope: 'scope.writePhotosAlbum',
  311. success() {
  312. console.log('授权成功')
  313. self.saveImg();
  314. },
  315. //用户拒绝
  316. fail() {
  317. console.log("用户再次拒绝")
  318. }
  319. })
  320. } else {
  321. self.saveImg();
  322. }
  323. }
  324. })
  325. },
  326. }
  327. }
  328. </script>
  329. <style lang="less" scoped>
  330. .canvaspopup-content {
  331. min-height: 750rpx;
  332. width: 600rpx;
  333. // padding: 20rpx 0rpx 130rpx;
  334. background-color: #33373f;
  335. box-sizing: border-box;
  336. position: relative;
  337. display: flex;
  338. flex-direction: column;
  339. .empty {
  340. flex: 1;
  341. display: flex;
  342. justify-content: center;
  343. align-items: center;
  344. color: @fontColor;
  345. }
  346. .poster-img {
  347. width: 100%;
  348. }
  349. .drawimg-canvas {
  350. // background-color: #fafafa;
  351. // zoom: 50%; // 将画布缩小到50%(最好通过像素比进行缩小,像素比是2的话就是50%,如果不全是以像素比为标准,在生成图片的时候可能会出现四周黑边)
  352. position: absolute;
  353. left: -10000px; // 将画布隐藏在可视区域外
  354. // top: 0;
  355. // background: #206949;
  356. }
  357. .footer {
  358. color: @fontColor;
  359. flex: 1;
  360. display: flex;
  361. justify-content: space-around;
  362. align-items: center;
  363. .btn {
  364. .combtn(28rpx, 72rpx);
  365. width: 160rpx;
  366. }
  367. }
  368. }
  369. </style>