|
- <template>
- <view class="container">
- <view
- class="image-box"
- :style="{
- backgroundImage: 'url('+ src +')',
- width: imageBoxWidth + 'px',
- height: imageBoxHeight + 'px',
- borderRadius: cropShape == 'rect' ? '' : ''
- }">
- <view class="mask"></view>
- <view
- class="cropping-box"
- @touchstart.stop="touchstart"
- @touchmove.stop="touchmove"
- :style="{
- top: cropBoxY + 'px',
- left: cropBoxX + 'px',
- width: cropBoxWidth + 'px',
- height: cropBoxHeight + 'px',
- backgroundImage: 'url('+ src +')',
- backgroundSize: imageBoxWidth + 'px' + ' ' + imageBoxHeight + 'px',
- backgroundPositionX: (-cropBoxX - 2) + 'px',
- backgroundPositionY: (-cropBoxY - 2) + 'px',
- borderRadius: cropShape == 'rect' ? '' : '50%'
- }"
- >
-
- <!-- <view v-if="cropShape == 'rect' && !isFixedSize" class="zoom-handle-rect" data-body="handle"></view> -->
- <!-- <view v-if="cropShape == 'circular'" class="zoom-chandle-circular" data-body="handle"></view> -->
- </view>
- </view>
-
- <!-- <canvas class="canvas" canvas-id="canvas" id="canvas" :style="{width: canvasWidth + 'px', height: canvasHeight + 'px'}"></canvas> -->
-
- <view class="operation-area">
- <!-- <view class="ratio-area" v-if="cropShape == 'rect'">
- <view class="ratio-btn" @click="setRatio('full')">full</view>
- <view class="ratio-btn" @click="setRatio(item)" v-for="item in ratioGroup">{{item}}</view>
- </view> -->
- <view class="crop-area">
- <!-- <u--image :src="cropImgPath" mode="widthFix" shape="circle" width="100px"
- height="100px"></u--image> -->
- </view>
- <view class="action">
- <!-- <view shape="circle" hover-class="none" class="btn" @click="cancel">取消</view> -->
- <view shape="circle" hover-class="none" class="btn full" @click="cropping">继续</view>
- </view>
- <!-- <view class="bottom">
- <u-button size="mini" @click="cancel">取消</u-button>
- <u-button size="mini" type="primary" @click="cropping">裁剪</u-button>
- </view> -->
- </view>
- </view>
- </template>
- <script>
-
- let startX, startY;
- let boxX, boxY, boxWidth, boxHeight;
- let imageOriginalWidth, imageOriginalHeight;
- let imageZoomRatio;
- let windowInfo;
-
- export default {
- name:'imageCropping',
- props: {
- src: {
- type: String,
- },
- ratioGroup: {
- type: Array,
- default(){
- return []
- }
- },
- isFixedSize: {
- type: Boolean,
- default:false
- },
- cropShape: {
- type: String,
- default: 'circular' // 'rect' , 'circular'
- }
- },
- data() {
- return {
- imageBoxWidth: 0,
- imageBoxHeight: 0,
- cropBoxX: 0,
- cropBoxY: 0,
- cropBoxWidth: 0,
- cropBoxHeight: 0,
- // move: 移动 , zoom: 缩放
- mode: '',
- cropSize: 100,
- cropImgPath: ''
- }
- },
- mounted(){
- this.getImageInfo();
- },
-
- methods:{
- // 获取图片尺寸
- getImageInfo() {
- windowInfo = uni.getWindowInfo();
- if (this.src) {
- uni.getImageInfo({
- src: this.src,
- success: (res) => {
- console.log("图片尺寸信息", res);
- imageOriginalWidth = res.width;
- imageOriginalHeight = res.height;
-
- let widthZoomRatio = imageOriginalWidth / windowInfo.windowWidth;
- let heightZoomRatio = imageOriginalHeight / windowInfo.windowHeight;
- imageZoomRatio = widthZoomRatio > heightZoomRatio ? widthZoomRatio : heightZoomRatio;
-
- this.imageBoxWidth = (imageOriginalWidth / imageZoomRatio);
- this.imageBoxHeight = (imageOriginalHeight / imageZoomRatio);
- this.setRatio('1:1');
- },
- fail: (error) => {
- console.log("error", error);
- }
- })
- }
-
- },
- touchstart(event){
- startX = event.touches[0].clientX;
- startY = event.touches[0].clientY;
-
- if(event.target.dataset.body == "handle"){
- this.mode = 'zoom';
- boxWidth = this.cropBoxWidth;
- boxHeight = this.cropBoxHeight;
- }else {
- this.mode = 'move';
- boxX = this.cropBoxX;
- boxY = this.cropBoxY;
- }
- },
- touchmove(event){
- let distanceX = event.touches[0].clientX - startX;
- let distanceY = event.touches[0].clientY - startY;
-
- let x = boxX + distanceX;
- let y = boxY + distanceY;
- let width = boxWidth + distanceX;
- let height = boxHeight + distanceY;
-
- let maxX = this.imageBoxWidth-this.cropBoxWidth;
- let maxY = this.imageBoxHeight-this.cropBoxHeight;
- let maxWidth = this.imageBoxWidth-this.cropBoxX;
- let maxHeight = this.imageBoxHeight-this.cropBoxY;
-
- switch (this.mode) {
- case 'move':
- this.cropBoxX = x < 0 ? 0 : (x > maxX ? maxX : x);
- this.cropBoxY = y < 0 ? 0 : (y > maxY ? maxY : y);
- break;
- case 'zoom':
- if(this.cropShape == 'rect'){
- this.cropBoxWidth = width > maxWidth ? maxWidth : width;
- this.cropBoxHeight = height > maxHeight ? maxHeight : height;
- }else{
- this.cropBoxHeight = height > maxHeight ? maxHeight : height;
- this.cropBoxWidth = height > maxHeight ? maxHeight : height;
- }
- break;
- }
- },
- setRatio(ratio){
- if(ratio == 'full'){
- this.cropBoxWidth = this.imageBoxWidth;
- this.cropBoxHeight = this.imageBoxHeight;
- this.cropBoxX = 0;
- this.cropBoxY = 0;
- }else{
- let x = ratio.split(':')[0];
- let y = ratio.split(':')[1];
- let r1 = (x/y);
- let r2 = (y/x);
-
- if(this.imageBoxWidth < this.imageBoxHeight){
- console.log("盒子宽度小于盒子高度");
- let size = this.imageBoxWidth;
- if(size / r1 > this.imageBoxHeight){
- size = this.imageBoxHeight;
- this.cropBoxWidth = (size / r2) - this.cropSize;
- this.cropBoxHeight = size - this.cropSize;
- this.cropBoxX = this.cropSize / 2;
- this.cropBoxY = (this.imageBoxWidth - this.imageBoxWidth) / 2;
- }else{
- this.cropBoxWidth = size - this.cropSize;
- this.cropBoxHeight = (size / r1) - this.cropSize;
- this.cropBoxX = this.cropSize / 2;
- this.cropBoxY = (this.imageBoxHeight - this.cropBoxHeight) / 2;
- }
- }else{
- let size = this.imageBoxHeight;
- if(size / r1 > this.imageBoxWidth){
- size = this.imageBoxWidth;
- this.cropBoxWidth = size - this.cropSize;
- this.cropBoxHeight = (size / r2) - this.cropSize;
- this.cropBoxX = ((this.imageBoxWidth - this.cropBoxWidth) / 2);
- this.cropBoxY = ((this.imageBoxHeight - this.cropBoxHeight) / 2);
- }else{
- this.cropBoxWidth =( size / r1) - this.cropSize;
- this.cropBoxHeight = size - this.cropSize;
- this.cropBoxX = ((this.imageBoxWidth - this.cropBoxWidth) / 2);
- this.cropBoxY = ((this.imageBoxWidth - this.cropBoxWidth) / 2);
- }
- }
- }
-
- },
- async cropping(){
- let x = this.cropBoxX * imageZoomRatio;
- let y = this.cropBoxY * imageZoomRatio;
- let w = this.cropBoxWidth * imageZoomRatio;
- let h = this.cropBoxHeight * imageZoomRatio;
-
- // 方式2:
- const canvas = uni.createOffscreenCanvas({type: '2d',width: w, height: h});
- const context = canvas.getContext('2d');
- context.fillStyle = '#fff'; // 设置绘制后的填充颜色
- context.globalCompositeOperation = 'source-over';
- const image = canvas.createImage();
- await new Promise((resolve,reject) => {
- image.onload = resolve
- image.onerror = reject
- image.src = this.src;
- image.backgroundColor = 'red'
- // image.src = "https://pic4.ntimg.cn/file/20191225/30544261_221404258307_1.jpg";
- })
- context.clearRect(0, 0, w, h);
- if(this.cropShape == 'circular'){
- context.beginPath();
- context.arc(w/2,h/2,w/2,0,Math.PI * 2);
- context.fill();
- context.clip();
- context.clip();
- }
- context.drawImage(image,x,y,w,h,0, 0, w, h);
-
- const DataURL = canvas.toDataURL();
-
- const fs = wx.getFileSystemManager();
- let tempFilePath = `${wx.env.USER_DATA_PATH}/` + new Date().getTime() + '.png'
- fs.writeFile({
- filePath: tempFilePath,
- data: DataURL.replace('data:image/png;base64,',''),
- encoding: 'base64',
- success: res => {
- this.$emit('completed',{
- tempFilePath
- });
- this.cropImgPath = tempFilePath;
- },
- fail(res) {
- console.error(res)
- }
- })
-
- // 方式一:
- // const context = uni.createCanvasContext('canvas', this)
- // context.drawImage(this.src,x,y,w,h,0, 0, w, h)
- // context.draw(false, ()=>{
- // console.log(123);
- // uni.canvasToTempFilePath({
- // canvas: context,
- // success: function(res) {
- // console.log(res)
- // },
- // complete: function(res){
- // console.log(res)
- // }
- // },this)
- // })
-
- },
- yuantu(){
- this.$emit('completed',{
- tempFilePath: this.src
- })
- },
- cancel(){
- this.$emit('cancel')
- }
- }
- }
-
- </script>
- <style lang="scss" scoped>
- .container{
- width: 100vw;
- height: 100vh;
- overflow: hidden;
- position: fixed;
- left: 0;
- top: 0;
- z-index: 99;
- display: flex;
- align-items: flex-start;
- justify-content: flex-start;
- background-color: #fff;
-
- .image-box{
- position: relative;
- background-size: contain;
- background-repeat: no-repeat;
- // filter: invert(1);
- z-index: 999;
-
- .mask{
- width: 100%;
- height: 100%;
- position: absolute;
- left: 0;
- top: 0;
- background-color: rgba(0, 0, 0, 0.4);
- z-index: 99;
- /* border-radius: 50%; */
- // backdrop-filter: blur(10px);
- }
- .cropping-box{
- position: absolute;
- border: 2px solid springgreen;
- box-sizing: border-box;
- z-index: 9999;
-
- // .zoom-handle-rect,
- // .zoom-chandle-circular{
- // width: 10px;
- // height: 10px;
- // background-color: springgreen;
- // border-radius: 50%;
- // position: absolute;
- // right: -6px;
- // bottom: -6px;
- // }
- .zoom-chandle-circular{
- right: 50%;
- transform: translateX(5px);
- }
-
- }
- }
- }
- .operation-area{
- position: fixed;
- bottom: 0;
- z-index: 1;
- width: 100%;
- padding: 10rpx 0;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
-
- .ratio-area{
- display: flex;
- align-items: center;
- justify-content: center;
- margin-bottom: 16rpx;
- .ratio-btn{
- display: inline-block;
- padding: 8rpx 20rpx;
- border: 2rpx solid white;
- color: white;
- margin: 0 10rpx;
- font-size: 12px;
- }
- }
- .bottom{
- height: 120rpx;
- width: 100%;
- display: flex;
- align-items: center;
- justify-content: center;
- button{
- display: inline-block;
- margin: 0 20rpx;
- }
- }
- .action {
- height: 120rpx;
- width: 100vw;
- position: fixed;
- bottom: 60rpx;
- left: 0;
- display: flex;
- justify-content: center;
- align-items: center;
- background: none;
- z-index: 9999;
-
- .btn {
- height: 89rpx;
- line-height: 89rpx;
- width: 266rpx;
- border: 4rpx solid #7F66E8;
- text-align: center;
- border-radius: 60rpx;
- font-family: OPPOSans;
- font-weight: bold;
- font-size: 36rpx;
- color: #7F66E8;
-
- &.full {
- background-color: #7F66E8;
- color: #FFFFFF;
- margin-left: 30rpx;
- font-weight: bold;
- }
- }
-
-
- }
-
- }
- .canvas{
- position: absolute;
- bottom: 0;
- left: 0;
- z-index: 1;
- border: 1px solid;
- // display: none;
- }
- </style>
|