Vue下的图片剪裁的资源

相关的用例的文章地址:Vue下的图片剪裁实例

	class Clip {
    //因为要保存到vue实例中,所以直接传一个$vm当闭包使用了
    constructor(wpId, $vm) {
        this.regional = document.getElementById(wpId);
        this.getImage = document.createElement('canvas');
        this.getImage.id = 'image-box';
        //将样式写入到创建节点的时候 -- 写在外面不会生效
        this.getImage.style.cssText = `
            position: absolute;
            left: 0px;
            right: 0px;
            bottom: 0px;
            top: 0px;
            margin: auto;
            box-sizing:border-box;
        `
        
        this.editBox = document.createElement('canvas');
        this.editBox.id = 'cover-box';
        this.editBox.style.cssText = `
            position: absolute;
            z-index: 9999;
            display: none;
            left: 0px;
            right: 0px;
            bottom: 0px;
            top: 0px; 
            margin: auto;
        `
            //在容器中加入这两个画布
        this.regional.appendChild(this.getImage);
        this.regional.appendChild(this.editBox);
        this.$vm = $vm; //整个vue实例
    }
    init(file) {
        this.sx = 0; //裁剪框的初始x
        this.sy = 0; //裁剪框的初始y
        this.sWidth = 233; //裁剪框的宽 -- 
        this.sHeight = 175; //裁剪框的高 
        this.chooseBoxScale = 233 / 175;
        this.handleFiles(file);
    }
    handleFiles(file) {
        let t = this;
        //FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。
        let reader = new FileReader();
        //readAsDataURL 方法会读取指定的 Blob 或 File 对象。读取操作完成的时候,readyState 会变成已完成DONE,并触发 loadend 事件,同时 result 属性将包含一个data:URL格式的字符串(base64编码)以表示所读取文件的内容。
        reader.readAsDataURL(file);
        reader.onload = function() {
            t.imgUrl = this.result;
            //this.result 是一个 将图片转成base64 格式后的字符串
            t.paintImg(this.result);
        }
    }
    paintImg(picUrl) {
        let t = this;
        let cxt = t.getImage.getContext('2d');

        //先清空画布
        cxt.clearRect(0, 0, this.getImage.width, this.getImage.height);

        //绘制图片
        let img = new Image();
        img.src = picUrl;
        img.onload = function() {
            //图片的宽高比例
            let imgScale = img.width / img.height;
            // t.regional 是容器节点
            // 盒子的宽高 -- 包括边框与内边距
            let boxScale = t.regional.offsetWidth / t.regional.offsetHeight;
            //判断盒子与图片的比列
            if (imgScale < boxScale) {
                //设置图片的像素
                t.imgWidth = t.regional.offsetHeight * imgScale;
                t.imgHeight = t.regional.offsetHeight;
            } else {
                //设置图片的像素
                t.imgWidth = t.regional.offsetWidth;
                t.imgHeight = t.regional.offsetWidth / imgScale;
            }

            //判断图片与选择框的比例大小,作出裁剪
            if (imgScale < t.chooseBoxScale) {
                //设置选择框的像素
                t.sWidth = t.imgWidth; //固定宽度
                t.sHeight = t.imgWidth / t.chooseBoxScale; // 业务需求的宽高比例

                //设置初始框的位置
                t.sx = 0;
                t.sy = (t.imgHeight - t.sHeight) / 2;
            } else {
                //设置选择框的像素
                t.sWidth = t.imgHeight * t.chooseBoxScale;
                t.sHeight = t.imgHeight; //固定高度

                t.sx = (t.imgWidth - t.sWidth) / 2;
                t.sy = 0;
            }

            //高分屏下图片模糊,需要2倍处理
            console.log(t.getImage)
            t.getImage.height = 2 * t.imgHeight;
            t.getImage.width = 2 * t.imgWidth;
            t.getImage.style.width = t.imgWidth + 'px';
            t.getImage.style.height = t.imgHeight + 'px';
            console.log(t.getImage)

            let vertSquashRatio = t.detectVerticalSquash(img);
            console.log(vertSquashRatio); //1

            console.log(2 * t.imgHeight)
            cxt.drawImage(img, 0, 0, 2 * t.imgWidth * vertSquashRatio, 2 * t.imgHeight * vertSquashRatio)
                //绘制图片以及剪裁区域
            t.cutImage();
            //拖拽这个剪裁区域
            t.drag();
        }
    }
    cutImage() {
            let t = this;

            //绘制遮罩层:
            t.editBox.height = 2 * t.imgHeight;
            t.editBox.width = 2 * t.imgWidth;

            t.editBox.style.display = 'block';
            t.editBox.style.width = t.imgWidth + 'px';
            t.editBox.style.height = t.imgHeight + 'px';

            let cover = t.editBox.getContext("2d");
            cover.fillStyle = "rgba(0, 0, 0, 0.7)";

            //画布的黑色填充
            cover.fillRect(0, 0, 2 * t.imgWidth, 2 * t.imgHeight);
            //剪裁图片的区域 这个位置点也是对的
            console.log("剪裁区域")
            cover.clearRect(2 * t.sx, 2 * t.sy, 2 * t.sWidth, 2 * t.sHeight);
        }
        //拖拽这个剪裁区域的时候
    drag() {
        let t = this;
        let draging = false;

        //记录初始点击的pageX,pageY。用于记录位移
        let pageX = 0;
        let pageY = 0;

        //初始位移
        let startX = 0;
        let startY = 0;


        t.editBox.addEventListener('touchmove', function(ev) {
            //移动端支持多指操作,0代表第0根手指
            let e = ev.touches[0];

            let offsetX = e.pageX - pageX;
            let offsetY = e.pageY - pageY;
            if (draging) {

                if (t.imgHeight == t.sHeight) {
                    console.log(t.imgHeight == t.sHeight)

                    t.sx = startX + offsetX;

                    if (t.sx <= 0) {
                        t.sx = 0;
                    } else if (t.sx >= t.imgWidth - t.sWidth) {
                        t.sx = t.imgWidth - t.sWidth;
                    }
                } else {
                    t.sy = startY + offsetY;

                    if (t.sy <= 0) {
                        t.sy = 0;
                    } else if (t.sy >= t.imgHeight - t.sHeight) {
                        t.sy = t.imgHeight - t.sHeight;
                    }
                }
                t.cutImage();
            }
        });
        t.editBox.addEventListener('touchstart', function(ev) {
            let e = ev.touches[0];
            draging = true;

            pageX = e.pageX; //记录滑动结束时候的坐标位置
            pageY = e.pageY;

            startX = t.sx;
            startY = t.sy;

        })
        t.editBox.addEventListener('touchend', function() {
            draging = false;
        })
    }
    save() {
            let t = this;
            let saveCanvas = document.createElement('canvas');
            let ctx = saveCanvas.getContext('2d');

            //图片裁剪后的尺寸
            saveCanvas.width = 466;
            saveCanvas.height = 350;

            let images = new Image();
            images.src = t.imgUrl;

            images.onload = function() {
                //计算裁剪尺寸比例,用于裁剪图片
                let cropWidthScale = images.width / t.imgWidth;
                let cropHeightScale = images.height / t.imgHeight;
                t.drawImageIOSFix(ctx, images, cropWidthScale * t.sx, cropHeightScale * t.sy,
                    t.sWidth * cropWidthScale, t.sHeight * cropHeightScale, 0, 0, 466, 350);
                //    ctx.drawImage(images,2 * t.sx, 2 * t.sy, t.sWidth * 2, t.sHeight * 2, 0, 0, 466, 350);
                // console.log(saveCanvas.toDataURL())
                //直接是链接
                t.$vm.showImgUrl = URL.createObjectURL(t.$vm.dataURLtoBlob(saveCanvas.toDataURL()));
                //接收的是文件
                t.$vm.recieveCipImg(t.$vm.dataURLtoFile(saveCanvas.toDataURL()));

                console.log(t.$vm)
                t.regional.removeChild(t.getImage);
                t.regional.removeChild(t.editBox);
            }
        }
        //用于修复ios下的canvas截图问题
        //详情可以看这里http://stackoverflow.com/questions/11929099/html5-canvas-drawimage-ratio-bug-ios
    detectVerticalSquash(img) {
        if (/png$/i.test(img.src)) {
            return 1;
        }
        //naturalWidth和naturalHeight是html5新增的属性,它们可以直接获取图片的原始宽高。而且这在Fixefox/Chrome/Safari/Opera/IE9里已经实现。
        let iw = img.naturalWidth,
            ih = img.naturalHeight;
        let canvas = document.createElement('canvas');
        canvas.width = 1;
        canvas.height = ih;
        let ctx = canvas.getContext('2d');
        console.log("我在这里绘制???")
        ctx.drawImage(img, 0, 0);
        //getImageData() 复制画布上指定矩形的像素数据,然后通过 putImageData() 将图像数据放回画布
        /**
         * 对于 ImageData 对象中的每个像素,都存在着四方面的信息,即 RGBA 值:
            R - 红色 (0-255)
            G - 绿色 (0-255)
            B - 蓝色 (0-255)
            A - alpha 通道 (0-255; 0 是透明的,255 是完全可见的)
            color/alpha 以数组形式存在,并存储于 ImageData 对象的 data 属性中。
        */
        //参数 x,y,width,height
        let data = ctx.getImageData(0, 0, 1, ih).data;

        let sy = 0;
        let ey = ih;
        let py = ih;
        while (py > sy) {
            const alpha = data[(py - 1) * 4 + 3];
            if (alpha === 0) {
                ey = py;
            } else {
                sy = py;
            }
            py = (ey + sy) >> 1;
        }
        const ratio = (py / ih);
        return (ratio === 0) ? 1 : ratio;
    }
    drawImageIOSFix(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh) {
            const vertSquashRatio = this.detectVerticalSquash(img);
            ctx.drawImage(img, sx * vertSquashRatio, sy * vertSquashRatio,
                sw * vertSquashRatio, sh * vertSquashRatio,
                dx, dy, dw, dh);
        }
        //转成 blob 对象
    dataURLtoBlob(dataurl) {
            var arr = dataurl.split(','),
                mime = arr[0].match(/:(.*?);/)[1],
                bstr = atob(arr[1]),
                n = bstr.length,
                u8arr = new Uint8Array(n);
            while (n--) {
                u8arr[n] = bstr.charCodeAt(n);
            }
            return new Blob([u8arr], { type: mime });
        }
        //转成 File 对象
    dataURLtoFile(dataurl) {
        var arr = dataurl.split(','),
            mime = arr[0].match(/:(.*?);/)[1],
            bstr = atob(arr[1]),
            n = bstr.length,
            u8arr = new Uint8Array(n);
        while (n--) {
            u8arr[n] = bstr.charCodeAt(n);
        }
        // 这里的 'share.png' 是自定义的文件名
        return new File([u8arr], 'share.png', { type: mime });
    }
}

export default Clip;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值