h5 canvas 图片上传操作
最近写的小 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 图片上传操作的更多相关文章
- 移动端H5实现图片上传
移动端H5实现图片上传 https://segmentfault.com/a/1190000010034177
- canvas图片上传相关学习
今天主要是研究了canvas的关于图片上传的相关知识, context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
- thinkphp3.2.3 ueditor1.4.3 图片上传操作,在线删除上传图片功能。
最近弄一个图片 上传,可是用ueditor 自带的上传,如果不配置的话,上传的目录不在自己的项目中. 在网上找了好多,可是都是底版本的,新版本的还真是找到了一个,ueditor-thinkphp 这个 ...
- H5 实现图片上传预览
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...
- ThinkPHP之中的图片上传操作
直接上个例子,其中包括有单图片文件上传.多图片文件上传.以及删除文件的一些操作.放置删除数据库的时候,仅仅删除掉了数据库之中的文件路径.而不是一并删除服务器之中的文件.放置服务器爆炸... TP里面c ...
- h5 端图片上传-模拟多张上传
1.由于后端的限制,上传图片到服务器只能的一张一张传2.显示图片预览是本地的图片3.根据服务器返回的结果拿到相应的路径保存到提交评论的接口中4.删除的时候,需要删除对应的路径,不要把删除的提交到评论的 ...
- h5 端图片上传
1.upload.js (function($) { $.extend($.fn, { images : new Array(), initImages:function (images) { $.e ...
- H5 选择图片上传及预览
<div class="sctp"> <img src="img/sczp.png" id="photo" alt=&qu ...
- vuejs开发组件分享之H5图片上传、压缩及拍照旋转的问题处理
一.前言 三年.net开发转前端已经四个月了,前端主要用webpack+vue,由于后端转过来的,前端不够系统,希望分享下开发心得与园友一起学习. 图片的上传之前都是用的插件(ajaxupload), ...
随机推荐
- javaScript基础的基础
JavaScript是一个脚本语言,需要有宿主文件,他的宿主文件是HTML文件. 与JAVA没有直接关系 一般写在 1.head里面 2.body里面 3.</html>后面 一般写在&l ...
- ABAP字符串的加密与解密
FIEB_PASSWORD_DECRYPT:字符串解密:FIEB_PASSWORD_ENCRYPT:字符串加密.旧版本的可以用. PARAMETERS:str1 type char32 OBLIGAT ...
- 用javascript和html5做一个音乐播放器,附带源码
效果图: 实现的功能 1.首页 2.底部播放控件 3.播放页面 4.播放列表 5.排行榜 6.音乐搜索 输入搜索关键词,点击放大镜图标 7.侧边栏 目录结构 开发心得与总结 1.轮播图 首先感谢作者S ...
- 面试总结之mysql
总结自己在面试过程遇到的数据库问题,以备不时之需. 1.你在你们公司用的什么版本的mysql数据库,用过mysql5.7吗? 在学校学习mysql的时候用的5.5,在公司的时候用的5.6,5.7还真没 ...
- Linux入门(5)——Ubuntu16.04安装网易云音乐
去网易云音乐官网下载deb包: http://music.163.com/#/download 打开终端: cd 下载 .0_amd64_ubuntu16..deb sudo apt-get -f i ...
- Javascript里的if判断与逻辑运算符(||, &&)和比较运算符的特别之处
写JS时不可避免要用到 if 与 逻辑运算符( ||, &&). 如果你经常阅读Js的第三方组件源码, 会发现有一种写法作为初始化变量的方法经常出现. var variable = v ...
- 安利一波那个叫做 hutool 的通用工具类库
摘自3.1.1版本作者发布原话,当时看到有点说不上的情绪,为作者的坚持.热爱点个赞. 已经想不起来是怎样结识 Hutool 的,但 Hutool 伴随几个项目的推进,获得了同事一致好评. 没经过实践和 ...
- LeetCode 380. Insert Delete GetRandom O(1) (插入删除和获得随机数 常数时间)
Design a data structure that supports all following operations in average O(1) time. insert(val): In ...
- Android Studio常见问题解决
1.Error:Execution failed for task ':XXXX:processDebugManifest'. > Manifest merger failed with mul ...
- 轻松学会ES6新特性之生成器
生成器虽然是ES6最具魔性的新特性,但也是最难懂得的一节,笔者写了大量的实例来具体化这种抽象的概念,能够让人一看就懂,目的是希望别人不要重复或者减少笔者学习生成器的痛苦经历. 在说具体的ES6生成器之 ...