h5 canvas 图片上传操作

 

最近写的小 demo,使用的是h5的 canvas来对图片进行放大,移动,剪裁等等
这是最原始的代码,比较接近我的思路,后续会再对格式和结构进行优化

html:

1 <pre name="code" class="brush: html;" rows="15" cols="300">
2 <input type="file" name="" accept="image/gif, image/jpeg" id="upload">
3 <canvas id="showimg" style="border:1px solid #aaa;"></canvas>
4 <p>移动:</p>     
5 <input type="range" min="0" max="2" id="move" step="0.01" value="1" class="range-control" oninput="translateall()"/><br/>
6 <button id="crop">剪裁输出</button>
7 <img id="img" src="" style="border:1px solid #aaa;">

 

 

js:初始代码

var img = new Image();
var can = document.getElementById('showimg');
var ctx = can.getContext("2d");
can.width = 500;
can.height = 400;
var fictitious_imgwidth,fictitious_imgheight,flag;
var distance_x = 0;
var distance_y = 0;
var orign_x,orign_y//鼠标点击时的坐标
var present_x,present_y//记录图片做上角的坐标
var substitute_x,substitute_y//暂时记录图片左上角坐标
ctx.fillStyle = "#aaa";   
ctx.fillRect(0,0,500,400); 
ctx.beginPath();
ctx.moveTo(100,100);   
ctx.lineTo(400,100);
ctx.lineTo(400,300);
ctx.lineTo(100,300); 
ctx.lineTo(100,100); 
ctx.lineWidth = 3;
ctx.strokeStyle = '#333'
ctx.stroke();
ctx.clip();
ctx.closePath();
ctx.clearRect(0, 0, can.width, can.height);   
$('#upload').change(function(){
    console.log('this is runing')
    ctx.clearRect(0, 0, can.width, can.height); 
    
    img.onload = function(){
        fictitious_imgwidth = img.width;
        fictitious_imgheight = img.height;
        present_x = can.width*0.5-img.width*0.5;
        present_y = can.height*0.5-img.height*0.5;
        ctx.drawImage(img,present_x,present_y,img.width,img.height);
    }
    img.src = getFileUrl('upload');
    
})
function translateall(){
    var val = document.getElementById("move").value;
    reprint(val)
}
function reprint(scale){
    ctx.clearRect(0, 0, can.width, can.height);
    fictitious_imgwidth = img.width*scale;
    fictitious_imgheight = img.height*scale;
    check_present();
    ctx.drawImage(img,present_x,present_y,fictitious_imgwidth,fictitious_imgheight)
}
function getFileUrl(sourceId) { 
    var url; 
    if (navigator.userAgent.indexOf("MSIE")>=1) { // IE 
        url = document.getElementById(sourceId).value; 
    } else if(navigator.userAgent.indexOf("Firefox")>0) { // Firefox 
        url = window.URL.createObjectURL(document.getElementById(sourceId).files.item(0)); 
    } else if(navigator.userAgent.indexOf("Chrome")>0) { // Chrome 
        url = window.URL.createObjectURL(document.getElementById(sourceId).files.item(0)); 
    }
    return url; 
} 
$('#showimg').mousedown(function(e){
    console.log('mousedown is running')
    orign_x = e.offsetX;
    orign_y = e.offsetY;
    judgment_isinimg(e);

}).mousemove(function(e){
    if(flag){
        distance_x = e.offsetX - orign_x;
        distance_y = e.offsetY - orign_y;
        ctx.clearRect(0, 0, can.width, can.height); 
        substitute_x = present_x + distance_x;
        substitute_y = present_y + distance_y;
        ctx.drawImage(img,substitute_x,substitute_y,fictitious_imgwidth,fictitious_imgheight);
        
    }
}).mouseleave(function(){
    flag = false
    present_x = substitute_x;
    present_y =substitute_y;
}).mouseup(function(){
    flag = false
    present_x = substitute_x;
    present_y =substitute_y;
})

function judgment_isinimg(e){
    var ll = present_x
    var lt = present_y
    var rl = present_x+fictitious_imgwidth
    var rt = present_y+fictitious_imgheight
    

    var x=event.clientX-can.getBoundingClientRect().left;
    var y=event.clientY-can.getBoundingClientRect().top;

    if(ll < x && x < rl && lt < y && y < rt){
        flag = true;
    }else{
        flag = false;
    }
}

function check_present(){
    if(typeof present_x == 'undefined' || typeof present_y == 'undefined'){
        present_x = can.width*0.5-fictitious_imgwidth*0.5;
        present_y = can.height*0.5-fictitious_imgheight*0.5;
    }
}

$('#crop').click(function(){
    crop_canvas = document.createElement('canvas');
    crop_canvas.width = 300;  
    crop_canvas.height = 200;
    crop_ctx =crop_canvas.getContext('2d')
    crop_ctx.fillStyle = "#fff";
    crop_ctx.fillRect(0,0,300,200);
    check_present();
    crop_ctx.drawImage(img,Number(present_x)-100,Number(present_y)-100,fictitious_imgwidth,fictitious_imgheight);
    var fullQuality = crop_canvas.toDataURL('image/jpeg', 1.0);
    $('#img').attr('src',fullQuality);
})
View Code

 

 修改后:

-(function($){
        var crop = {
            init:function(){
                this.img = new Image();
                this.can = document.getElementById('showimg');
                var ctx = this.ctx = this.can.getContext("2d");
                this.width = this.can.width = 500;
                this.height = this.can.height = 400;
                ctx.fillStyle = "#aaa";  
                ctx.fillRect(0,0,500,400); 
                ctx.beginPath();
                ctx.moveTo(100,100);   
                ctx.lineTo(400,100);
                ctx.lineTo(400,300);
                ctx.lineTo(100,300); 
                ctx.lineTo(100,100); 
                ctx.lineWidth = 3;
                ctx.strokeStyle = '#333'
                ctx.stroke();
                ctx.clip();
                ctx.closePath();
                this.clear();  
                this.addListen();
            },
            change:function(){
                this.clear();
                this.img.onload = function(){
                    var $this = crop;
                    $this.img_width = $this.img.width;
                    $this.img_height = $this.img.height;
                    $this.fictitious_imgwidth = $this.img_width;
                    $this.fictitious_imgheight = $this.img_height;
                    $this.present_x = $this.width*0.5-$this.img_width*0.5;
                    $this.present_y = $this.height*0.5-$this.img_height*0.5;
                    $this.ctx.drawImage($this.img,$this.present_x,$this.present_y,$this.img_width,$this.img_height);
                }
                this.img.src = this.getFileUrl('upload');
            },
            translate:function(){
                var val = document.getElementById("move").value;
                this.clear();
                this.fictitious_imgwidth = this.img_width*val;
                this.fictitious_imgheight = this.img_height*val;
                this.ctx.drawImage(this.img,this.present_x,this.present_y,this.fictitious_imgwidth,this.fictitious_imgheight);
            },
            mouseDown:function(e){
                this.orign_x = e.offsetX;
                this.orign_y = e.offsetY;
                this.judgmentIsInImg(e);
            },
            mouseMove:function(e){
                var e = e || event;
                if(this.flag){
                    this.distance_x = e.offsetX - this.orign_x;
                    this.distance_y = e.offsetY - this.orign_y;
                    this.clear();
                    this.substitute_x = this.present_x + this.distance_x;
                    this.substitute_y = this.present_y + this.distance_y;
                    this.ctx.drawImage(this.img,this.substitute_x,this.substitute_y,this.fictitious_imgwidth,this.fictitious_imgheight);
                }
            },
            mouseLeave:function(){
                if(this.flag){
                    this.present_x = this.substitute_x;
                    this.present_y = this.substitute_y;
                    this.flag = false;
                }
                
            },
            out:function(){
                var crop_canvas = document.createElement('canvas');
                crop_canvas.width = 300;  
                crop_canvas.height = 200;
                crop_ctx = crop_canvas.getContext('2d');
                crop_ctx.fillStyle = "#fff";
                crop_ctx.fillRect(0,0,300,200);
                crop_ctx.drawImage(this.img,Number(this.present_x)-100,Number(this.present_y)-100,this.fictitious_imgwidth,this.fictitious_imgheight);
                var fullQuality = crop_canvas.toDataURL('image/jpeg', 1.0);
                $('#img').attr('src',fullQuality);
            },
            judgmentIsInImg:function(e){
                var e = e || event;
                var ll = this.present_x;
                var lt = this.present_y;
                var rl = this.present_x+this.fictitious_imgwidth;
                var rt = this.present_y+this.fictitious_imgheight;
                
                var x=e.clientX-this.can.getBoundingClientRect().left;
                var y=e.clientY-this.can.getBoundingClientRect().top;

                if(ll < x && x < rl && lt < y && y < rt){
                    this.flag = true;
                }else{
                    this.flag = false;
                }
                
            },
            clear:function(){
                this.ctx.clearRect(0, 0, this.width, this.height);
            },
            getFileUrl:function(id){
                var url;
                try{
                    if (navigator.userAgent.indexOf("MSIE")>=1) { // IE 
                        url = document.getElementById(id).value; 
                    } else if(navigator.userAgent.indexOf("Firefox")>0) { // Firefox 
                        url = window.URL.createObjectURL(document.getElementById(id).files.item(0)); 
                    } else if(navigator.userAgent.indexOf("Chrome")>0) { // Chrome 
                        url = window.URL.createObjectURL(document.getElementById(id).files.item(0)); 
                    }
                }catch(e){
                    throw new Error('you can ignore it')
                }
                return url;
            },
            addListen:function(){
                $('#upload').on('change',this.change.bind(this));
                $('#move').on('input',this.translate.bind(this));
                $('#showimg').on('mousedown',this.mouseDown.bind(this))
                .on('mousemove',this.mouseMove.bind(this))
                .on('mouseleave mouseup',this.mouseLeave.bind(this));
                $('#crop').on('click',this.out.bind(this));
            }
        }
        return crop.init();
    })(jQuery)
View Code

 

如果还有何不足,请多多指正

 

12.16日修改 因为最近讨论到了头像上传,剪裁的问题,我又对此进行了回顾,发现该 demo 也有不足之处,所以我花了点时间重新修改一下再添加了注释:

最新代码:

-(function($) {
    var crop = {
        init: function() {
            this.img = new Image();
            this.can = document.getElementById('showimg');
            var ctx = this.ctx = this.can.getContext("2d");
            this.width = this.can.width = 500;
            this.height = this.can.height = 400;
            ctx.fillStyle = "#aaa";
            ctx.fillRect(0, 0, 500, 400);
            ctx.beginPath();
            ctx.moveTo(100, 100);
            ctx.lineTo(400, 100);
            ctx.lineTo(400, 300);
            ctx.lineTo(100, 300);
            ctx.lineTo(100, 100);
            ctx.lineWidth = 3;
            ctx.strokeStyle = '#333'
            ctx.stroke();
            ctx.clip();
            ctx.closePath();
            this.clear();
            this.addListen();
        },
        render(src) {
            this.img = new Image();
            this.img.onload = function() {
                var $this = crop;
                $this.img_width = $this.img.width; //原图像横坐标
                $this.img_height = $this.img.height; //原图像纵坐标
                $this.fictitious_imgwidth = $this.img_width; //被缩放的图像横坐标
                $this.fictitious_imgheight = $this.img_height; //被缩放的图像纵坐标
                //因为后面图像的变化后长度都不是原长度了,后面使用图像长度是就使用fictitious属性
                $this.init_x = $this.width * 0.5; //图片中心点横坐标
                $this.init_y = $this.height * 0.5; //图片中心点纵坐标
                //绘图时同过中心点减去fictitious/2长度来确定图像左上角的坐标
                $this.ctx.drawImage($this.img, $this.init_x - $this.img_width / 2, $this.init_y - $this.img_height / 2, $this.img_width, $this.img_height);
            };
            this.img.src = src;
        },
        change: function() {
            this.clear();
            $('#move').val(1) //根据实际需要进行初始化
            var reader = new FileReader();
            var img = $('#upload').get(0).files[0];

            reader.onload = function(e) {
                crop.render(e.target.result);
            };

            reader.readAsDataURL(img);
        },
        translate: function() {
            var val = document.getElementById("move").value;
            this.clear();
            this.fictitious_imgwidth = this.img_width * val;
            this.fictitious_imgheight = this.img_height * val;
            this.ctx.drawImage(this.img, this.init_x - this.fictitious_imgwidth / 2, this.init_y - this.fictitious_imgheight / 2, this.fictitious_imgwidth, this.fictitious_imgheight);
        },
        mouseDown: function(e) {
            this.orign_x = e.offsetX;
            this.orign_y = e.offsetY;
            this.judgmentIsInImg(e); //判断点击是否在图像内
        },
        mouseMove: function(e) {
            var e = e || event;
            if (this.flag) {
                this.distance_x = e.offsetX - this.orign_x; //鼠标移动的长度
                this.distance_y = e.offsetY - this.orign_y;
                this.clear();
                this.substitute_x = this.init_x + this.distance_x;
                this.substitute_y = this.init_y + this.distance_y;
                this.ctx.drawImage(this.img, this.substitute_x - this.fictitious_imgwidth / 2, this.substitute_y - this.fictitious_imgheight / 2, this.fictitious_imgwidth, this.fictitious_imgheight);
            }
        },
        mouseLeave: function() {
            if (this.flag) {
                this.init_x = this.substitute_x;
                this.init_y = this.substitute_y;
                this.flag = false;
            }

        },
        out: function() {
            //输出图像
            var crop_canvas = document.createElement('canvas');
            crop_canvas.width = 300;
            crop_canvas.height = 200;
            crop_ctx = crop_canvas.getContext('2d');
            crop_ctx.fillStyle = "#fff";
            crop_ctx.fillRect(0, 0, 300, 200);
            crop_ctx.drawImage(this.img, this.init_x - this.fictitious_imgwidth / 2 - 100, this.init_y - this.fictitious_imgheight / 2 - 100, this.fictitious_imgwidth, this.fictitious_imgheight);
            //这边的减去100 是原 canvas 阴影边框的长度
            var fullQuality = crop_canvas.toDataURL('image/jpeg', 1.0);
            $('#img').attr('src', fullQuality);
        },
        judgmentIsInImg: function(e) {
            var e = e || event;

            var ll = this.init_x - this.fictitious_imgwidth / 2;
            var lt = this.init_y - this.fictitious_imgheight / 2;
            var rl = this.init_x + this.fictitious_imgwidth / 2;
            var rt = this.init_y + this.fictitious_imgheight / 2;
            //图像四个角的坐标

            var x = e.clientX - this.can.getBoundingClientRect().left;
            var y = e.clientY - this.can.getBoundingClientRect().top;

            if (ll < x && x < rl && lt < y && y < rt) {
                this.flag = true;
            } else {
                this.flag = false;
            }

        },
        clear: function() {
            this.ctx.clearRect(0, 0, this.width, this.height);
        },
        addListen: function() {
            $('#upload').on('change', this.change.bind(this));
            $('#move').on('input', this.translate.bind(this));
            $('#showimg').on('mousedown', this.mouseDown.bind(this))
                .on('mousemove', this.mouseMove.bind(this))
                .on('mouseleave mouseup', this.mouseLeave.bind(this));
            $('#crop').on('click', this.out.bind(this));
        }
    }
    return crop.init();
})(jQuery)

 

 

修改之后,进行缩放时不是原来的按左上角坐标缩放,而是按图像中心缩放,因为这样的缩放方式,所以不能靠记录图像左上角坐标进行绘制,而是记录图像中心点位置,还解决了手机端的图片获取兼容问题,原来的获取图片 url 方法只能在 PC端有效;

gitHub:https://github.com/Grewer/JsDemo/tree/master/crop

demo:https://grewer.github.io/JsDemo/crop/crop.html

如果这篇文章帮助到了你,请给我一个 star

 

posted @ 2017-06-25 00:44  Grewer  阅读(2558)  评论(0编辑  收藏  举报