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

html:

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

修改后:

-(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)

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

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

h5 canvas 图片上传操作的更多相关文章

  1. 移动端H5实现图片上传

    移动端H5实现图片上传 https://segmentfault.com/a/1190000010034177

  2. canvas图片上传相关学习

    今天主要是研究了canvas的关于图片上传的相关知识, context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);  

  3. thinkphp3.2.3 ueditor1.4.3 图片上传操作,在线删除上传图片功能。

    最近弄一个图片 上传,可是用ueditor 自带的上传,如果不配置的话,上传的目录不在自己的项目中. 在网上找了好多,可是都是底版本的,新版本的还真是找到了一个,ueditor-thinkphp 这个 ...

  4. H5 实现图片上传预览

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  5. ThinkPHP之中的图片上传操作

    直接上个例子,其中包括有单图片文件上传.多图片文件上传.以及删除文件的一些操作.放置删除数据库的时候,仅仅删除掉了数据库之中的文件路径.而不是一并删除服务器之中的文件.放置服务器爆炸... TP里面c ...

  6. h5 端图片上传-模拟多张上传

    1.由于后端的限制,上传图片到服务器只能的一张一张传2.显示图片预览是本地的图片3.根据服务器返回的结果拿到相应的路径保存到提交评论的接口中4.删除的时候,需要删除对应的路径,不要把删除的提交到评论的 ...

  7. h5 端图片上传

    1.upload.js (function($) { $.extend($.fn, { images : new Array(), initImages:function (images) { $.e ...

  8. H5 选择图片上传及预览

    <div class="sctp"> <img src="img/sczp.png" id="photo" alt=&qu ...

  9. vuejs开发组件分享之H5图片上传、压缩及拍照旋转的问题处理

    一.前言 三年.net开发转前端已经四个月了,前端主要用webpack+vue,由于后端转过来的,前端不够系统,希望分享下开发心得与园友一起学习. 图片的上传之前都是用的插件(ajaxupload), ...

随机推荐

  1. 当谈到 GitLab CI 的时候,我们该聊些什么(上篇)

    "微服务"这个概念近两年非常热,正在慢慢改变 DevOps 的思路.微服务架构把一个庞大的业务系统拆解开来,每一个组件变得更加独立自治.松耦合.但是,同时也伴随着部署单元粒度越来越 ...

  2. 容器平台选型的十大模式:Docker、DC/OS、K8S 谁与当先?

    作者:刘超   来自:网易云 基础服务 无论是在社区,还是在同客户交流的过程中,总会被问到到底什么时候该用 Docker?什么时候用虚拟机?如果使用容器,应该使用哪个容器平台? 显而易见,我不会直接给 ...

  3. python之集合

    集合(set),它是一个无序的,不重复的数据组合,它是作用如下: 1.去重,也就是去除重复的内容.有一点值得注意的是:将一个列表(list)变成集合的时候,会自动去重. 2.关系测试.测试数据之间的交 ...

  4. 笨鸟先飞之ASP.NET MVC系列之过滤器(06异常过滤器)

    概念介绍 异常过滤器主要在我们方法中出现异常的时候触发,一般我们用 异常过滤器 记录日志,或者在产生异常时做友好的处理 如果我们需要创建异常过滤器需要实现IExceptionFilter接口. nam ...

  5. PhiloGL学习(1)——场景创建及方块欲露还羞出水面

    前言 上一篇文章中介绍了我认识PhiloGL框架的机缘以及初步的探讨(见JS前端三维地球渲染--中国各城市航空路线展示),在此文中仅仅对此框架进行了简单介绍并初步介绍了一些该框架的知识.首先三维这个东 ...

  6. Web前端性能优化——如何有效提升静态文件的加载速度

    WeTest 导读 此文总结了笔者在Web静态资源方面的一些优化经验. 一.如何优化 用户在访问网页时, 最直观的感受就是页面内容出来的速度,我们要做的优化工作, 也主要是为了这个目标.那么为了提高页 ...

  7. LeetCode 605. Can Place Flowers (可以种花)

    Suppose you have a long flowerbed in which some of the plots are planted and some are not. However, ...

  8. LeetCode 81. Search in Rotated Sorted Array II(在旋转有序序列中搜索之二)

    Follow up for "Search in Rotated Sorted Array":What if duplicates are allowed? Would this ...

  9. js获取本地ip和地区

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. 编程&blog处女篇-用C#求100以内的质数

    using System;namespace Loops{ class Program { static void Main(string[] args) { /*局部变量定义*/ int i, j; ...