Преглед изворни кода

开发生成动漫风格图片

bayi пре 1 година
родитељ
комит
eacb28b088

+ 11 - 0
api/avatar.js

@@ -0,0 +1,11 @@
+import {
+    aiRequest
+} from "../utils/request";
+module.exports = {
+    // 风格列表查询
+    getLoraList: data => aiRequest('/paint/lora/list', 'get', data),
+    // 图片生成接口
+    createAiImg: data => aiRequest('/api/paint/generate', 'post', data),
+    // 风格列表查询
+    getTaskResult: data => aiRequest('/paint/task', 'post', data),
+}

+ 1 - 0
app.json

@@ -1,5 +1,6 @@
 {
     "pages": [
+        "pages/aiAvatar/index",
         "pages/index/index",
         "pages/activity/index",
         "pages/message/index",

+ 689 - 0
components/yeyouzi-cropper/yeyouzi-cropper.js

@@ -0,0 +1,689 @@
+// components/yeyouzi-cropper/yeyouzi-cropper.js
+let success;
+let fail;
+Component({
+    /**
+     * 组件的属性列表
+     */
+    properties: {
+
+    },
+
+    /**
+     * 组件的初始数据
+     */
+    data: {
+        canvas: '',
+        ctx: '',
+        dpr: '',
+        x1: 0,
+        y1: 0,
+        x2: 0,
+        y2: 0,
+        k1: 0,
+        m1: 0,
+        k2: 0,
+        m2: 0,
+        cutMove: false,
+        endCut: {
+            x: 0,
+            y: 0
+        },
+        movePoint: '0',
+        img: {
+            path: '',
+            width: 0,
+            height: 0,
+            type: 1 // 1:横向 2:纵向
+        },
+        imageWidth: 0,
+        imageHeight: 0,
+        imageLeft: 0,
+        imageTop: 0,
+        imgRotate: 0,
+        imgMirror: 0,
+        originWidthShow: 0.5,
+        originHeightShow: 0.5,
+        imgMove: false,
+        imgStart: {
+            x: 0,
+            y: 0,
+            left: 0,
+            top: 0,
+            distance: 0,
+            width: 0,
+            height: 0,
+            cutImg: ''
+        },
+        imgScale: false,
+
+        cutImg: {
+            path: '',
+            x: 0,
+            y: 0,
+            width: 0,
+            height: 0
+        }
+
+
+    },
+
+    /**
+     * 组件的方法列表
+     */
+    methods: {
+        /**
+         * 公有方法
+         */
+
+        //初始化
+        init(param) {
+            success = param.success
+            fail = param.fail
+            var that = this;
+            this.setData({
+                img: {
+                    path: param.imgPath
+                }
+            })
+            const query = wx.createSelectorQuery().in(this)
+            query.select('#cutCanvas')
+                .fields({
+                    node: true,
+                    size: true
+                })
+                .exec((res) => {
+                    const canvas = res[0].node
+                    const ctx = canvas.getContext('2d')
+                    const dpr = wx.getSystemInfoSync().pixelRatio
+                    canvas.width = res[0].width * dpr
+                    canvas.height = res[0].height * dpr
+                    ctx.scale(dpr, dpr)
+
+                    var x1 = canvas.width * 0.15 / dpr;
+                    var y1 = (canvas.height - canvas.width * 0.7) / 2 / dpr;
+                    var x2 = x1 + canvas.width * 0.7 / dpr;
+                    var y2 = y1 + canvas.width * 0.7 / dpr;
+                    var k1 = (y2 - y1) / (x2 - x1);
+                    var m1 = (x2 * y1 - x1 * y2) / (x2 - x1)
+                    var k2 = (y1 - y2) / (x2 - x1);
+                    var m2 = (x2 * y2 - x1 * y1) / (x2 - x1);
+                    that.setData({
+                        canvas: canvas,
+                        ctx: ctx,
+                        dpr: dpr,
+                        x1: x1,
+                        y1: y1,
+                        x2: x2,
+                        y2: y2,
+                        k1: k1,
+                        m1: m1,
+                        k2: k2,
+                        m2: m2
+                    })
+                    this._drawCut(x1, y1, x2, y2)
+                    wx.getImageInfo({
+                        src: param.imgPath,
+                        success(img) {
+                            var width = '';
+                            var height = '';
+                            var type = 0;
+                            var x = '';
+                            var y = '';
+                            var d = '';
+                            if (img.width > img.height) {
+                                height = that.data.y2 - that.data.y1;
+                                width = (img.width * height) / img.height
+                                type = 1
+                                d = img.height
+                                x = (img.width - d) / 2
+                                y = 0
+                            } else {
+                                width = that.data.x2 - that.data.x1;
+                                height = (img.height * width) / img.width
+                                type = 2
+                                d = img.width
+                                x = 0
+                                y = (img.height - d) / 2
+                            }
+                            that.setData({
+                                img: {
+                                    path: param.imgPath,
+                                    width: img.width,
+                                    height: img.height,
+                                    type: type
+                                },
+                                cutImg: {
+                                    x: x,
+                                    y: y,
+                                    width: d,
+                                    height: d
+                                },
+                                imageWidth: ((x2 - x1) / d) * img.width,
+                                imageHeight: ((y2 - y1) / d) * img.height,
+                                imageLeft: x1 - ((x2 - x1) / d) * x,
+                                imageTop: y1 - ((y2 - y1) / d) * y,
+                                imgRotate: 0
+                            })
+                        }
+                    })
+                })
+
+        },
+
+        /**
+         * 私有方法
+         */
+        _drawCut(x1, y1, x2, y2) {
+            var ctx = this.data.ctx;
+            var canvas = this.data.canvas;
+            ctx.clearRect(0, 0, canvas.width, canvas.height)
+            ctx.globalAlpha = '0.5'
+            ctx.fillStyle = '#000000'
+            ctx.fillRect(0, 0, canvas.width, canvas.height)
+
+            ctx.strokeStyle = '#ffffff'
+            ctx.lineWidth = '3'
+            ctx.lineCap = 'square'
+            ctx.globalAlpha = '1'
+            ctx.strokeRect(x1, y1, x2 - x1, y2 - y1)
+            ctx.fillStyle = '#ffffff'
+            ctx.fillRect(x1 - 5, y1 - 5, 20, 20) //左上角 1
+            ctx.fillRect(x2 - 15, y1 - 5, 20, 20) //右上角 2
+            ctx.fillRect(x1 - 5, y2 - 15, 20, 20) //左下角 3
+            ctx.fillRect(x2 - 15, y2 - 15, 20, 20) //右下角 4
+            ctx.clearRect(x1, y1, x2 - x1, y2 - y1)
+        },
+
+        _touchStart(e) {
+            //裁剪框是否移动
+            var flag = false;
+            var point = '0'
+            if (e.touches[0].x >= this.data.x1 - 10 && this.data.x1 + 10 >= e.touches[0].x) {
+                if (e.touches[0].y >= this.data.y1 - 10 && this.data.y1 + 10 >= e.touches[0].y) {
+                    flag = true;
+                    point = '1';
+                    this.setData({
+                        endCut: {
+                            x: this.data.x1,
+                            y: this.data.y1
+                        }
+                    })
+                } else if (e.touches[0].y >= this.data.y2 - 10 && this.data.y2 + 10 >= e.touches[0].y) {
+                    flag = true;
+                    point = '3';
+                    this.setData({
+                        endCut: {
+                            x: this.data.x1,
+                            y: this.data.y2
+                        }
+                    })
+                }
+            } else if (e.touches[0].x >= this.data.x2 - 10 && this.data.x2 + 10 >= e.touches[0].x) {
+                if (e.touches[0].y >= this.data.y1 - 10 && this.data.y1 + 10 >= e.touches[0].y) {
+                    flag = true;
+                    point = '2'
+                    this.setData({
+                        endCut: {
+                            x: this.data.x2,
+                            y: this.data.y1
+                        }
+                    })
+                } else if (e.touches[0].y >= this.data.y2 - 10 && this.data.y2 + 10 >= e.touches[0].y) {
+                    flag = true;
+                    point = '4'
+                    this.setData({
+                        endCut: {
+                            x: this.data.x2,
+                            y: this.data.y2
+                        }
+                    })
+                }
+            }
+            this.setData({
+                cutMove: flag,
+                movePoint: point
+            })
+
+            //图片是否移动
+            if (e.touches[0].x >= this.data.x1 + 10 && this.data.x2 - 10 >= e.touches[0].x) {
+                if (e.touches[0].y >= this.data.y1 + 10 && this.data.y2 - 10 >= e.touches[0].y) {
+                    if (e.touches.length == 1) {
+                        this.setData({
+                            imgMove: true,
+                            imgStart: {
+                                x: e.touches[0].x,
+                                y: e.touches[0].y,
+                                left: this.data.imageLeft,
+                                top: this.data.imageTop
+                            },
+                            imgScale: false
+                        })
+                    } else if (e.touches.length == 2) {
+                        this.setData({
+                            imgMove: false,
+                            imgStart: {
+                                distance: Math.sqrt(Math.pow(e.touches[1].x - e.touches[0].x, 2) + Math.pow(e.touches[1].y - e.touches[0].y, 2)),
+                                width: this.data.imageWidth,
+                                height: this.data.imageHeight,
+                                cutImg: this.data.cutImg
+                            },
+                            imgScale: true
+                        })
+                    }
+                }
+            }
+        },
+
+        _touchMove(e) {
+            if (this.data.cutMove) {
+                var x1;
+                var y1;
+                var x2;
+                var y2;
+                if (this.data.movePoint == '1') {
+                    x1 = e.touches[0].x
+                    y1 = this.data.k1 * x1 + this.data.m1
+                    x2 = this.data.x2
+                    y2 = this.data.y2
+                    if (x1 > x2 - 100) {
+                        x1 = x2 - 100
+                        y1 = this.data.k1 * x1 + this.data.m1
+                    } else if (x1 < this.data.x1) {
+                        x1 = this.data.x1
+                        y1 = this.data.k1 * x1 + this.data.m1
+                    }
+                    this.setData({
+                        endCut: {
+                            x: x1,
+                            y: y1
+                        }
+                    })
+                } else if (this.data.movePoint == '2') {
+                    x2 = e.touches[0].x
+                    y1 = this.data.k2 * x2 + this.data.m2
+                    x1 = this.data.x1
+                    y2 = this.data.y2
+                    if (x2 > this.data.x2) {
+                        x2 = this.data.x2
+                        y1 = this.data.y1
+                    } else if (x2 < this.data.x1 + 100) {
+                        x2 = this.data.x1 + 100
+                        y1 = this.data.k2 * x2 + this.data.m2
+                    }
+                    this.setData({
+                        endCut: {
+                            x: x2,
+                            y: y1
+                        }
+                    })
+                } else if (this.data.movePoint == '3') {
+                    x1 = e.touches[0].x
+                    y2 = this.data.k2 * x1 + this.data.m2
+                    x2 = this.data.x2
+                    y1 = this.data.y1
+                    if (x1 > x2 - 100) {
+                        x1 = x2 - 100
+                        y2 = this.data.k2 * x1 + this.data.m2
+                    } else if (x1 < this.data.x1) {
+                        x1 = this.data.x1
+                        y2 = this.data.y2
+                    }
+                    this.setData({
+                        endCut: {
+                            x: x1,
+                            y: y2
+                        }
+                    })
+                } else if (this.data.movePoint == '4') {
+                    x2 = e.touches[0].x
+                    y2 = this.data.k1 * x2 + this.data.m1
+                    x1 = this.data.x1
+                    y1 = this.data.y1
+                    if (x2 > this.data.x2) {
+                        x2 = this.data.x2
+                        y2 = this.data.k1 * x2 + this.data.m1
+                    } else if (x2 < x1 + 100) {
+                        x2 = x1 + 100
+                        y2 = this.data.k1 * x2 + this.data.m1
+                    }
+                    this.setData({
+                        endCut: {
+                            x: x2,
+                            y: y2
+                        }
+                    })
+                }
+                this._drawCut(x1, y1, x2, y2)
+            } else if (this.data.imgMove) {
+                var dx = this.data.imgStart.x - e.touches[0].x
+                var dy = this.data.imgStart.y - e.touches[0].y
+                var rotate = this.data.imgRotate
+                var left = this.data.imgStart.left - dx
+                var top = this.data.imgStart.top - dy
+                if (this.data.imgMirror == 180) {
+                    dx = -dx
+                    rotate = -rotate
+                }
+                var tx = dx * Math.cos(rotate * Math.PI / 180) + dy * Math.sin(rotate * Math.PI / 180)
+                var ty = dy * Math.cos(rotate * Math.PI / 180) - dx * Math.sin(rotate * Math.PI / 180)
+                var x = (tx + this.data.originWidthShow * this.data.imageWidth) / this.data.imageWidth * this.data.img.width - this.data.cutImg.width / 2
+                var y = (ty + this.data.originHeightShow * this.data.imageHeight) / this.data.imageHeight * this.data.img.height - this.data.cutImg.height / 2
+                this.setData({
+                    cutImg: {
+                        width: this.data.cutImg.width,
+                        height: this.data.cutImg.height,
+                        x: x,
+                        y: y
+                    },
+                    imageLeft: left,
+                    imageTop: top,
+                })
+            } else if (this.data.imgScale) {
+                var nowDistance = Math.sqrt(Math.pow(e.touches[1].x - e.touches[0].x, 2) + Math.pow(e.touches[1].y - e.touches[0].y, 2))
+                var m = nowDistance / this.data.imgStart.distance
+                var width = this.data.imgStart.width * m
+                var height = this.data.imgStart.height * m
+                if (this.data.img.type == 1) {
+                    height = height < this.data.y2 - this.data.y1 ? this.data.y2 - this.data.y1 : height
+                    height = height > (this.data.y2 - this.data.y1) * 10 ? (this.data.y2 - this.data.y1) * 10 : height
+                    width = (height * this.data.img.width) / this.data.img.height
+                } else {
+                    width = width < this.data.x2 - this.data.x1 ? this.data.x2 - this.data.x1 : width
+                    width = width > (this.data.x2 - this.data.x1) * 10 ? (this.data.x2 - this.data.x1) * 10 : width
+                    height = (width * this.data.img.height) / this.data.img.width
+                }
+                var n = width / this.data.imgStart.width
+                var cut = {
+                    x: this.data.imgStart.cutImg.x + ((n - 1) / (2 * n)) * this.data.imgStart.cutImg.width,
+                    y: this.data.imgStart.cutImg.y + ((n - 1) / (2 * n)) * this.data.imgStart.cutImg.height,
+                    width: this.data.imgStart.cutImg.width / n,
+                    height: this.data.imgStart.cutImg.height / n
+                }
+                var left = this.data.x1 - ((this.data.x2 - this.data.x1) / cut.width) * cut.x
+                left = left > this.data.x1 ? this.data.x1 : left
+                left = left < this.data.x2 - this.data.imageWidth ? this.data.x2 - this.data.imageWidth : left
+                var top = this.data.y1 - ((this.data.y2 - this.data.y1) / cut.height) * cut.y
+                top = top > this.data.y1 ? this.data.y1 : top
+                top = top < this.data.y2 - this.data.imageHeight ? this.data.y2 - this.data.imageHeight : top
+                this.setData({
+                    imageLeft: left,
+                    imageTop: top,
+                    imageWidth: width,
+                    imageHeight: height,
+                    cutImg: {
+                        x: cut.x,
+                        y: cut.y,
+                        width: cut.width,
+                        height: cut.height
+                    },
+                })
+            }
+        },
+
+        _touchEnd(e) {
+            if (this.data.cutMove) {
+                var dx;
+                var dy;
+                var d;
+                var movePoint = this.data.movePoint
+                if (movePoint % 2 == 0) {
+                    d = ((this.data.endCut.x - this.data.x1) * this.data.cutImg.width) / (this.data.x2 - this.data.x1)
+                    if (this.data.imgMirror == 180) {
+                        dx = -(this.data.endCut.x - this.data.x2) / this.data.imageWidth * this.data.img.width / 2
+                        if (movePoint == '2') {
+                            dy = (this.data.endCut.y - this.data.y1) / this.data.imageHeight * this.data.img.height / 2
+                        } else {
+                            dy = (this.data.endCut.y - this.data.y2) / this.data.imageHeight * this.data.img.height / 2
+                        }
+                    } else {
+                        dx = (this.data.endCut.x - this.data.x2) / this.data.imageWidth * this.data.img.width / 2
+                        if (movePoint == '2') {
+                            dy = (this.data.endCut.y - this.data.y1) / this.data.imageHeight * this.data.img.height / 2
+                        } else {
+                            dy = (this.data.endCut.y - this.data.y2) / this.data.imageHeight * this.data.img.height / 2
+                        }
+                    }
+                } else {
+                    d = ((this.data.x2 - this.data.endCut.x) * this.data.cutImg.width) / (this.data.x2 - this.data.x1)
+                    if (this.data.imgMirror == 180) {
+                        dx = -(this.data.endCut.x - this.data.x1) / this.data.imageWidth * this.data.img.width / 2
+                        if (movePoint == '1') {
+                            dy = (this.data.endCut.y - this.data.y1) / this.data.imageHeight * this.data.img.height / 2
+                        } else {
+                            dy = (this.data.endCut.y - this.data.y2) / this.data.imageHeight * this.data.img.height / 2
+                        }
+                    } else {
+                        dx = (this.data.endCut.x - this.data.x1) / this.data.imageWidth * this.data.img.width / 2
+                        if (movePoint == '1') {
+                            dy = (this.data.endCut.y - this.data.y1) / this.data.imageHeight * this.data.img.height / 2
+                        } else {
+                            dy = (this.data.endCut.y - this.data.y2) / this.data.imageHeight * this.data.img.height / 2
+                        }
+                    }
+                }
+                var rotate = this.data.imgMirror == 180 ? -this.data.imgRotate : this.data.imgRotate
+                var x = ((dx * Math.cos(rotate * Math.PI / 180) + dy * Math.sin(rotate * Math.PI / 180)) + this.data.originWidthShow * this.data.img.width) - d / 2
+                var y = ((dy * Math.cos(rotate * Math.PI / 180) - dx * Math.sin(rotate * Math.PI / 180)) + this.data.originHeightShow * this.data.img.height) - d / 2
+                this.setData({
+                    cutImg: {
+                        x: x,
+                        y: y,
+                        width: d,
+                        height: d
+                    },
+                    imageWidth: ((this.data.x2 - this.data.x1) / d) * this.data.img.width,
+                    imageHeight: ((this.data.y2 - this.data.y1) / d) * this.data.img.height,
+                    imageLeft: this.data.x1 - ((this.data.x2 - this.data.x1) / d) * x,
+                    imageTop: this.data.y1 - ((this.data.y2 - this.data.y1) / d) * y,
+
+                })
+                this._drawCut(this.data.x1, this.data.y1, this.data.x2, this.data.y2)
+            }
+            if (this.data.imgMove) {
+                var left = this.data.x1 - ((this.data.x2 - this.data.x1) / this.data.cutImg.width) * this.data.cutImg.x
+                var top = this.data.y1 - ((this.data.y2 - this.data.y1) / this.data.cutImg.height) * this.data.cutImg.y
+                this.setData({
+                    imageLeft: left,
+                    imageTop: top,
+                })
+            }
+            this.setData({
+                originWidthShow: (this.data.cutImg.x + this.data.cutImg.width / 2) / this.data.img.width,
+                originHeightShow: (this.data.cutImg.y + this.data.cutImg.height / 2) / this.data.img.height,
+                cutMove: false,
+                movePoint: '0',
+                imgMove: false,
+                imgScale: false
+            })
+        },
+
+        _rotateChange(e) {
+            this.setData({
+                imgRotate: e.detail.value
+            })
+        },
+
+        /*  _rotateNinety() {
+             var r = this.data.imgRotate + 90 > 180 ? this.data.imgRotate - 270 : this.data.imgRotate + 90
+             this.setData({
+                 imgRotate: r
+             })
+         }, */
+
+        /*   _imageMirror() {
+              var m = this.data.imgMirror == 180 ? 0 : 180
+              this.setData({
+                  imgMirror: m,
+              })
+          }, */
+
+        /*   _imgRestore(){
+            this.setData({
+              canvas: '',
+              ctx: '',
+              x1: 0,
+              y1: 0,
+              x2: 0,
+              y2: 0,
+              k1: 0,
+              m1: 0,
+              k2: 0,
+              m2: 0,
+              cutMove: false,
+              endCut: {
+                x: 0,
+                y: 0
+              },
+              movePoint: '0',
+              imageWidth: 0,
+              imageHeight: 0,
+              imageLeft: 0,
+              imageTop: 0,
+              imgRotate: 0,
+              imgMirror: 0,
+              originWidthShow: 0.5,
+              originHeightShow: 0.5,
+              imgMove: false,
+              imgStart: {
+                x: 0,
+                y: 0,
+                left: 0,
+                top: 0,
+                distance: 0,
+                width: 0,
+                height: 0,
+                cutx: 0,
+                cuty: 0
+              },
+              imgScale: false,
+              cutImg: {
+                path: '',
+                x: 0,
+                y: 0,
+                width: 0,
+                height: 0
+              }
+            })
+            this.init(this.data.img.path)
+          }, */
+
+        _cancelCut() {
+            this._restoreData()
+            if (fail) {
+                fail('cancel')
+            }
+        },
+
+        _confirmCut() {
+            wx.showLoading({
+                title: '裁剪中...',
+                mask: true
+            })
+            var that = this
+            const query = wx.createSelectorQuery().in(this)
+            query.select('#imgCanvas')
+                .fields({
+                    node: true,
+                    size: true
+                })
+                .exec((res) => {
+                    const canvas = res[0].node
+                    const ctx = canvas.getContext('2d')
+                    canvas.width = that.data.cutImg.width
+                    canvas.height = that.data.cutImg.height
+                    ctx.translate(canvas.width / 2, canvas.height / 2)
+                    ctx.rotate((that.data.imgRotate >= 0 ? that.data.imgRotate : that.data.imgRotate + 360) * Math.PI / 180)
+                    if (that.data.imgMirror == 180) {
+                        ctx.scale(-1, 1); //左右镜像翻转
+                    }
+                    const img = canvas.createImage()
+                    img.src = that.data.img.path
+                    img.onload = () => {
+                        ctx.drawImage(img, 0, 0, that.data.img.width, that.data.img.height, -(that.data.cutImg.x + canvas.width / 2), -(that.data.cutImg.y + canvas.height / 2), that.data.img.width, that.data.img.height)
+                        wx.canvasToTempFilePath({
+                            canvas: canvas,
+                            success(img) {
+                                success(img.tempFilePath)
+                                that._restoreData()
+                                wx.hideLoading({
+                                    success: (res) => {},
+                                })
+                            },
+                            fail(res) {
+                                console.log(res, '裁剪失败');
+                                wx.hideLoading({
+                                    success: (res) => {
+                                        wx.showToast({
+                                            title: '裁剪失败',
+                                            icon: 'error'
+                                        })
+                                        if (fail) {
+                                            fail('fail')
+                                        }
+                                    },
+                                })
+                            }
+                        })
+                    }
+                })
+
+        },
+
+        _restoreData() {
+            this.setData({
+                canvas: '',
+                ctx: '',
+                x1: 0,
+                y1: 0,
+                x2: 0,
+                y2: 0,
+                k1: 0,
+                m1: 0,
+                k2: 0,
+                m2: 0,
+                cutMove: false,
+                endCut: {
+                    x: 0,
+                    y: 0
+                },
+                movePoint: '0',
+                img: {
+                    path: '',
+                    width: 0,
+                    height: 0,
+                    type: 1 // 1:横向 2:纵向
+                },
+                imageWidth: 0,
+                imageHeight: 0,
+                imageLeft: 0,
+                imageTop: 0,
+                imgRotate: 0,
+                imgMirror: 0,
+                originWidthShow: 0.5,
+                originHeightShow: 0.5,
+                imgMove: false,
+                imgStart: {
+                    x: 0,
+                    y: 0,
+                    left: 0,
+                    top: 0,
+                    distance: 0,
+                    width: 0,
+                    height: 0,
+                    cutx: 0,
+                    cuty: 0
+                },
+                imgScale: false,
+
+                cutImg: {
+                    path: '',
+                    x: 0,
+                    y: 0,
+                    width: 0,
+                    height: 0
+                }
+            })
+        },
+    }
+})

+ 4 - 0
components/yeyouzi-cropper/yeyouzi-cropper.json

@@ -0,0 +1,4 @@
+{
+  "component": true,
+  "usingComponents": {}
+}

+ 32 - 0
components/yeyouzi-cropper/yeyouzi-cropper.wxml

@@ -0,0 +1,32 @@
+<view class="Container-show" wx:if="{{img.path != ''}}">
+    <view class="imgContainer">
+        <canvas type="2d" id="cutCanvas" style="width: 100%;height: 100%;z-index:9999;" bindtouchstart="_touchStart"
+            bindtouchend="_touchEnd" bindtouchmove="_touchMove"></canvas>
+        <view
+            style="position: absolute;top:{{imageTop}}px;left: {{imageLeft}}px;transform: rotateY({{imgMirror}}deg);transform-origin:{{originWidthShow * 100}}% {{originHeightShow * 100}}%;">
+            <image src="{{img.path}}"
+                style="width:{{imageWidth}}px;height:{{imageHeight}}px;transform: rotateZ({{imgMirror == 180 ? -imgRotate : imgRotate}}deg);transform-origin:{{originWidthShow * 100}}% {{originHeightShow * 100}}%;">
+            </image>
+        </view>
+
+    </view>
+    <view class="settingContainer">
+        <view class="rotate" style="color: #fff;width: 100%;text-align: center;">旋转{{imgRotate}}°</view>
+        <view class="rotateContainer">
+            <text style="color: #fff;font-size: 32rpx;">-180°</text>
+            <slider style="width: 100%;" min="-180" max="180" value="{{imgRotate}}" block-size="18px"
+                selected-color="#fff" bindchanging="_rotateChange"></slider>
+            <text style="color: #fff;font-size: 32rpx;">180°</text>
+        </view>
+
+        <view class="btnContainer">
+            <text style="color: #fff;font-size: 34rpx;" bindtap="_cancelCut">取消</text>
+            <!--    <text style="color: #fff;font-size: 16px;text-align:center;align-self: center;" bindtap="_imgRestore">还原</text> -->
+            <text style="color: #fff;font-size: 34rpx;" bindtap="_confirmCut">确定</text>
+        </view>
+
+    </view>
+
+    <canvas type="2d" id="imgCanvas" class='imgCanvas'></canvas>
+
+</view>

+ 58 - 0
components/yeyouzi-cropper/yeyouzi-cropper.wxss

@@ -0,0 +1,58 @@
+.Container {
+    opacity: 0;
+    z-index: -9999;
+    display: flex;
+    flex-direction: column;
+    width: 100%;
+    height: 100%;
+    position: fixed;
+    left: 0;
+    top: 0;
+}
+
+.Container-show {
+    position: fixed;
+    left: 0;
+    top: 0;
+    background: #000;
+    display: flex;
+    width: 100%;
+    height: 100%;
+    flex-direction: column;
+    opacity: 1;
+    z-index: 999;
+}
+
+.imgContainer {
+    height: 100%;
+    width: 100%;
+    position: relative;
+}
+
+.settingContainer {
+    background: #000;
+    padding: 40rpx 0;
+    z-index: 10000;
+}
+
+.rotateContainer {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    padding: 0px 40rpx;
+    margin-bottom: 190rpx;
+}
+
+.btnContainer {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    padding: 40rpx;
+}
+
+.imgCanvas {
+    position: absolute;
+    top: -9999px;
+    width: 600rpx;
+    height: 600rpx;
+}

+ 185 - 0
pages/aiAvatar/index.js

@@ -0,0 +1,185 @@
+import {
+    getLoraList,
+    createAiImg,
+    getTaskResult,
+} from '~/api/avatar'
+import {
+    userEvent
+} from '~/api/global'
+Page({
+    data: {
+        templates: [],
+        loading: false,
+        active: '',
+        artistic: '',
+        original: ''
+    },
+    onLoad() {
+        getLoraList().then(res => {
+            this.setData({
+                templates: res.loras,
+                active: res.loras[0] ? res.loras[0].lora_id : ''
+            })
+        })
+    },
+    async selectTemplate({
+        currentTarget
+    }) {
+        if (this.data.loading) {
+            return
+        }
+        this.setData({
+            active: currentTarget.dataset.id
+        })
+        if (this.data.original) {
+            this.createAiImg()
+        }
+        /*   await userEvent({
+              action: "style",
+              id: currentTarget.dataset.name
+          }) */
+    },
+    uploadImg() {
+        if (this.data.loading) {
+            return
+        }
+        wx.chooseMedia({
+            count: 1,
+            mediaType: ['image'],
+            sizeType: ['compressed'], //  original 原图;compressed 压缩图
+            sourceType: ['album', 'camera'],
+            camera: 'back',
+            success: (res) => {
+                this.cropper = this.selectComponent("#cropper");
+                this.cropper.init({
+                    imgPath: res.tempFiles[0].tempFilePath, //imgPath是需要裁剪图片的图片路径,只支持本地或临时路径
+                    success: (imgUrl) => {
+                        wx.getFileSystemManager().readFile({
+                            filePath: imgUrl,
+                            encoding: "base64",
+                            success: res => {
+                                //返回base64格式
+                                var base64Str = 'data:image/png' + ';base64,' + res.data
+                                this.setData({
+                                    artistic: base64Str,
+                                    original: base64Str
+                                })
+                                this.createAiImg()
+                                /* userEvent({
+                                    action: "photo"
+                                }) */
+                            },
+                            fail: err => {
+                                console.log(err)
+                            }
+                        })
+                    },
+                    fail(error) {
+                        console.log(error) //有两种:cancel代表点击了叉,fail代表wx.canvasToTempFilePath生成图片失败
+                    }
+                });
+            }
+        })
+    },
+    createAiImg() {
+        if (!this.data.original || this.data.loading) {
+            return
+        }
+        this.setData({
+            loading: true
+        })
+        createAiImg({
+            "width": 512, //生成图片宽度
+            "height": 512, //生成图片高度
+            "n_samples": 1, //生成图片数量
+            "controlnet_input_image_base64": this.data.original, //控制图片base64编码
+            "style_id": this.data.active //控制风格id
+        }).then(res => {
+            this.getAiImg(res.uuid)
+        }).catch(() => {
+            this.setData({
+                loading: false
+            })
+            wx.showToast({
+                title: '网络异常请重试',
+                icon: 'none',
+                duration: 2500
+            })
+        })
+    },
+    async getAiImg(uuid) {
+        console.log(uuid, 'uuuid');
+        let res = await getTaskResult({
+            uuid
+        })
+        if (res.data.status != 2) {
+            setTimeout(() => {
+                this.getAiImg(uuid)
+            }, 2500)
+        } else {
+            this.setData({
+                loading: false,
+                artistic: res.data.generated_imgs[0]
+            })
+        }
+    },
+    downloadImg() {
+        wx.getSetting({
+            success: (res) => {
+                if (res.authSetting['scope.writePhotosAlbum']) {
+                    this.base64ToImg()
+                } else {
+                    wx.authorize({
+                        scope: 'scope.writePhotosAlbum',
+                        success: () => {
+                            this.base64ToImg()
+                        },
+                        fail(res) {
+                            wx.showModal({
+                                title: '无法保存到相册',
+                                content: '点击右上角浮点按钮->设置,进行授权',
+                                confirmText: '我知道了',
+                                showCancel: false,
+                            })
+                        }
+                    })
+                }
+            }
+        })
+    },
+    base64ToImg() {
+        const base64 = this.data.artistic; //base64格式图片
+        if (!base64 || this.data.loading) {
+            return
+        }
+        const time = new Date().getTime();
+        const imgPath = wx.env.USER_DATA_PATH + "/poster" + time + "" + ".png";
+        //如果图片字符串不含要清空的前缀,可以不执行下行代码.
+        const imageData = base64.replace(/^data:image\/\w+;base64,/, "");
+        const file = wx.getFileSystemManager();
+        file.writeFileSync(imgPath, imageData, "base64");
+        wx.saveImageToPhotosAlbum({
+            filePath: imgPath,
+            success: async (res) => {
+                wx.showModal({
+                    title: '照片已保存至相册',
+                    content: '快去分享给小伙伴吧',
+                    confirmText: '我知道了',
+                    showCancel: false,
+                })
+                /*   await userEvent({
+                      action: 'save'
+                  }) */
+            }
+        })
+    },
+    onShareAppMessage() {
+        /* userEvent({
+            action: 'share'
+        }) */
+        return {
+            title: '玩转AI头像',
+            path: '/pages/index/index',
+        }
+    }
+})

+ 5 - 0
pages/aiAvatar/index.json

@@ -0,0 +1,5 @@
+{
+    "usingComponents": {
+        "cropper": "/components/yeyouzi-cropper/yeyouzi-cropper"
+    }
+}

+ 141 - 0
pages/aiAvatar/index.less

@@ -0,0 +1,141 @@
+.container {
+    position: relative;
+    min-height: 100vh;
+    background-color: #3609B8;
+    overflow: hidden;
+
+    .headerBg {
+        position: absolute;
+        width: 100%;
+        height: 598rpx;
+    }
+
+    .body {
+        position: relative;
+        z-index: 2;
+        margin: 206rpx auto 36rpx;
+        width: 700rpx;
+
+        .uploadBox {
+            position: relative;
+            width: 100%;
+            height: 790rpx;
+
+            .uploadBg {
+                width: 100%;
+                height: 100%;
+            }
+
+            .loading {
+                position: absolute;
+                width: 100%;
+                top: 300rpx;
+                text-align: center;
+                z-index: 3;
+                color: white;
+
+                .loadingImg {
+                    width: 110rpx;
+                    height: 110rpx;
+                    animation: identifier 2.6s infinite linear;
+                }
+
+                .tips1 {
+                    margin: 42rpx 0rpx 42rpx;
+                    font-size: 34rpx;
+                }
+
+                .tips2 {
+                    font-size: 26rpx;
+                }
+            }
+
+            .fillImg {
+                position: absolute;
+                width: 660rpx;
+                height: 642rpx;
+                left: 22rpx;
+                top: 118rpx;
+                border-radius: 20rpx;
+                object-fit: cover;
+            }
+
+            .imgMask::before {
+                position: absolute;
+                content: "";
+                width: 660rpx;
+                height: 642rpx;
+                background-color: rgba(0, 0, 0, 0.4);
+            }
+        }
+
+        .templateBox {
+            margin-top: 30rpx;
+
+            .tHeaderBg {
+                width: 700rpx;
+                height: 48rpx;
+            }
+
+            .templates {
+                position: relative;
+                width: 100%;
+                // height: 236rpx;
+                border-radius: 20rpx;
+
+                .tbg {
+                    position: absolute;
+                    z-index: -1;
+                    width: 100%;
+                    height: 100%;
+                }
+
+                .templateScroll {
+                    width: 100%;
+                    padding: 36rpx 0 6rpx 16rpx;
+                    white-space: nowrap;
+                    box-sizing: border-box;
+
+                    .template {
+                        margin-right: 10rpx;
+                        display: inline-block;
+
+                        .cover {
+                            width: 140rpx;
+                            height: 140rpx;
+                            margin-right: 20rpx;
+                            background-color: white;
+                            border-radius: 10rpx;
+                        }
+
+                        .name {
+                            margin-top: 12rpx;
+                            width: 140rpx;
+                            color: white;
+                            text-align: center;
+                            font-size: 26rpx;
+                        }
+                        .active {
+                            border: 4rpx solid #FDD841;
+                            box-sizing: border-box;
+                        }
+                    }
+
+                }
+            }
+        }
+    }
+
+    .btns {
+        width: 700rpx;
+        margin: 0 auto 40rpx;
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+
+        .btn {
+            width: 285rpx;
+            height: 82rpx;
+        }
+    }
+}

+ 37 - 0
pages/aiAvatar/index.wxml

@@ -0,0 +1,37 @@
+<view class="container">
+    <image src="/static/ai/headerBg.jpg" class="headerBg" />
+    <view class="body">
+        <view class="uploadBox" bindtap="uploadImg">
+            <image src="/static/ai/uploadBg.png" class="uploadBg" />
+            <view class="loading" wx:if="{{loading}}">
+                <image src="/static/ai/loading.png" class="loadingImg" />
+                <view class="tips1">
+                    图片生成中
+                </view>
+                <view class="tips2">
+                    正在制作中请稍等
+                </view>
+            </view>
+            <image src="{{artistic}}" class="fillImg {{loading?'imgMask':''}}" />
+        </view>
+        <view class="templateBox">
+            <image src="/static/ai/tHeaderBg.png" class="tHeaderBg" />
+            <view class="templates">
+                <image src="/static/ai/tbg.png" class="tbg" />
+                <scroll-view class="templateScroll" scroll-x="true" enhanced show-scrollbar="{{false}}">
+                    <view class="template" wx:for="{{templates}}" wx:key="index" bindtap="selectTemplate"
+                        data-id='{{item.lora_id}}'   data-name='{{item.name}}'>
+                        <image src="https://ai.wx.aidomore.com/v3/image/thumbnail/{{item.cover}}"
+                            class="cover {{item.lora_id==active?'active':''}}" />
+                        <view class="name textOver">{{item.name}}</view>
+                    </view>
+                </scroll-view>
+            </view>
+        </view>
+    </view>
+    <view class="btns">
+        <image src="/static/ai/reset.png" class="btn" bindtap="uploadImg" />
+        <image src="/static/ai/download.png" class="btn" bindtap="downloadImg" />
+    </view>
+    <cropper id="cropper" style="width: 100%;height: 100%;"></cropper>
+</view>

+ 119 - 0
pages/aiAvatar/index.wxss

@@ -0,0 +1,119 @@
+.container {
+  position: relative;
+  min-height: 100vh;
+  background-color: #3609B8;
+  overflow: hidden;
+}
+.container .headerBg {
+  position: absolute;
+  width: 100%;
+  height: 598rpx;
+}
+.container .body {
+  position: relative;
+  z-index: 2;
+  margin: 206rpx auto 36rpx;
+  width: 700rpx;
+}
+.container .body .uploadBox {
+  position: relative;
+  width: 100%;
+  height: 790rpx;
+}
+.container .body .uploadBox .uploadBg {
+  width: 100%;
+  height: 100%;
+}
+.container .body .uploadBox .loading {
+  position: absolute;
+  width: 100%;
+  top: 300rpx;
+  text-align: center;
+  z-index: 3;
+  color: white;
+}
+.container .body .uploadBox .loading .loadingImg {
+  width: 110rpx;
+  height: 110rpx;
+  animation: identifier 2.6s infinite linear;
+}
+.container .body .uploadBox .loading .tips1 {
+  margin: 42rpx 0rpx 42rpx;
+  font-size: 34rpx;
+}
+.container .body .uploadBox .loading .tips2 {
+  font-size: 26rpx;
+}
+.container .body .uploadBox .fillImg {
+  position: absolute;
+  width: 660rpx;
+  height: 642rpx;
+  left: 22rpx;
+  top: 118rpx;
+  border-radius: 20rpx;
+  object-fit: cover;
+}
+.container .body .uploadBox .imgMask::before {
+  position: absolute;
+  content: "";
+  width: 660rpx;
+  height: 642rpx;
+  background-color: rgba(0, 0, 0, 0.4);
+}
+.container .body .templateBox {
+  margin-top: 30rpx;
+}
+.container .body .templateBox .tHeaderBg {
+  width: 700rpx;
+  height: 48rpx;
+}
+.container .body .templateBox .templates {
+  position: relative;
+  width: 100%;
+  border-radius: 20rpx;
+}
+.container .body .templateBox .templates .tbg {
+  position: absolute;
+  z-index: -1;
+  width: 100%;
+  height: 100%;
+}
+.container .body .templateBox .templates .templateScroll {
+  width: 100%;
+  padding: 36rpx 0 6rpx 16rpx;
+  white-space: nowrap;
+  box-sizing: border-box;
+}
+.container .body .templateBox .templates .templateScroll .template {
+  margin-right: 10rpx;
+  display: inline-block;
+}
+.container .body .templateBox .templates .templateScroll .template .cover {
+  width: 140rpx;
+  height: 140rpx;
+  margin-right: 20rpx;
+  background-color: white;
+  border-radius: 10rpx;
+}
+.container .body .templateBox .templates .templateScroll .template .name {
+  margin-top: 12rpx;
+  width: 140rpx;
+  color: white;
+  text-align: center;
+  font-size: 26rpx;
+}
+.container .body .templateBox .templates .templateScroll .template .active {
+  border: 4rpx solid #FDD841;
+  box-sizing: border-box;
+}
+.container .btns {
+  width: 700rpx;
+  margin: 0 auto 40rpx;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+.container .btns .btn {
+  width: 285rpx;
+  height: 82rpx;
+}

BIN
static/ai/download.png


BIN
static/ai/headerBg.jpg


BIN
static/ai/loading.png


BIN
static/ai/reset.png


BIN
static/ai/tHeaderBg.png


BIN
static/ai/tbg.png


BIN
static/ai/upload.png


BIN
static/ai/uploadBg.png


+ 35 - 0
utils/request.js

@@ -58,6 +58,41 @@ function request(url, method, data, oldBaseUrl = false, intercept = true) {
         })
     })
 }
+
+function aiRequest(url, method, data) {
+    return new Promise((reslove, reject) => {
+        wx.request({
+            url: 'https://ai.wx.aidomore.com/v3' + url,
+            method,
+            data,
+            timeout: 60000,
+            header: {
+                'uid': wx.getStorageSync('uid') || '',
+            },
+            success: (result) => {
+                let {
+                    statusCode,
+                    data
+                } = result
+                if (statusCode == '200') {
+                    reslove(data)
+                } else {
+                    wx.showToast({
+                        title: '服务异常请稍后重试',
+                        icon: "none",
+                        duration: 3000
+                    })
+                }
+            },
+            fail: (res) => {
+                console.error(res)
+                reject(res)
+            },
+        })
+    })
+}
+
 module.exports = {
     request,
+    aiRequest
 }