HTML5本地图片裁剪并上传

最近做了一个项目,这个项目中需要实现的一个功能是:用户自定义头像(用户在本地选择一张图片,在本地将图片裁剪成满足系统要求尺寸的大小)。这个功能的需求是:头像最初剪切为一个正方形。如果选择的图片小于规定的头像要求尺寸,那么这整张图片都会作为头像。如果大于规定的尺寸,那么用户可以选择要裁剪的区域。用户点击确定按钮,就将裁剪得到的图片数据发送到服务器,在后端将图片数据保存成一个文件。

要完成上述功能,涉及到的知识有:ajax,canvas和html5中的files接口。我将实现这个功能的代码封装到了4个模块中,分别是ajax.js,preview.js,shear.js和customerImg.js。

ajax.js:用于发送ajax请求。

preview.js:用于图片预览

shear.js:用于裁剪图片

customer.js:自定义头像。在这个模块中药引入ajax.js,preview.js和shear.js

我使用webpack进行打包。我还使用了jquery和jquery-ui。

我从这个项目中抽离出了这个功能。下面是这个功能的详细代码。

1.HTML代码

<div class="m-warp" id="warp"><div class="item"><input type="file" name="img" id="img" hidden><label for="img">选择图片</label></div><div class="item clearfix"><div class="col col-1"><div class="preview" id="preview"><div class="mask"></div><canvas class="cvsMove" id="cvsMove"></canvas></div></div><div class="thum col-2 col"><p>预览</p><img src="" id="thum"><p class="f-text-l f-marTop-20"><button class="shear" id="submit">确定</button></p></div></div></div>

2.CSS代码

.clearfix:after{content: "";display: block;clear: both;height: 0;overflow: hidden;visibility: hidden;
}
img{
  vertical-align: middle;
  max-width:100%
} .m-warp{width: 800px; } .item{margin-top: 20px; } .col{float: left; } .col-1{position: relative;width: 450px;height: 450px;outline: 1px solid #333; } .preview{display: inline-block; } .col-2{width: 300px;margin-left: 50px; } label{display: block;text-align: center;width: 100px;font-size: 16px;color: #fff;background-color: #888888;height: 30px;line-height: 30px; } .mask{position: absolute;z-index: 1;top:0;left: 0;bottom: 0;right: 0;background-color: rgba(0,0,0,.4); } .cvsMove{position: absolute;z-index: 2;outline: 2px dotted #333;cursor: move;display: none; }

有了css和html的运行结果如下:

3.js代码

customerImg.js

var $ = require('jquery');
var ajax = require('./ajax.js');
var preview = require('./preview.js');
var shear = require('./shear.js');
/*** 自定义头像* @constructor*/
function CustomerImg() {this.isSupport = null;this.previewBox = null;this.warp = null;
}
/*** 入口* @param warp 操作区域 jquery节点*/
CustomerImg.prototype.start = function (warp) {var info,me,warpBox;me = this;this.isSupport = this.__isSupport();if(!this.isSupport) {info = $('<p>你的浏览器不支持自定义头像,可更换高版本的浏览器自定义头像</p>');$('body').html(info);return this;}//判断操作区域示范存在if(warp && warp.length > 0){this.warp = warp;}else{return this;}//预览
    preview.start(warp,shear.start.bind(shear,warp));this.previewBox = warp.find('#preview');//确定
    warp.find('#submit').unbind('click').on('click',me.__submit.bind(me));
};
/*** 提交* @private*/
CustomerImg.prototype.__submit = function () {var cvsMove,data,fd;cvsMove = this.previewBox.find('#cvsMove');data = cvsMove[0].toDataURL('image/jpg',1);fd = {'customerImg':data};ajax.upload(fd);
};
/*** 判断是否支持自定义头像* @returns {boolean}* @private*/
CustomerImg.prototype.__isSupport = function () {var canvas,context;canvas= document.createElement('canvas');if(typeof FileReader === 'function'&& canvas.getContext && canvas.toDataURL){return true;}else{return false;}
};
var customerImg = new CustomerImg();
module.exports = customerImg;

preview.js

/*** Created by star on 2017/3/7.*/
var $ = require('jquery');
/*** 预览类* @constructor*/
function Preview() {this.boxElem = null;this.callback = null;this.type = null;
}
/*** 入口* @param boxElem 操作区域* @param callback 预览结束的回调函数*/
Preview.prototype.start = function (boxElem,callback) {var chooseFile,me;me = this;if(! boxElem || boxElem.length <= 0) return this;this.boxElem = boxElem;if(typeof callback === 'function'){this.callback = callback;}if(this.__isSupport()){chooseFile = boxElem.find('input[type="file"]');chooseFile.on('change',me.fileChange.bind(me))}
};
/*** 选择图片的事件处理程序* @param event*/
Preview.prototype.fileChange = function (event) {var target,reader,file,me,type;target =  event.target;me = this;file = target.files[0];type = file.type;this.type = type;if(type !== 'image/png' && type !== 'image/jpg' && type !== 'image/jpeg'){alert('文件格式不正确');return this;}reader = new FileReader();if(file){reader.readAsDataURL(file);}reader.onload = function () {me.show(reader);}
};
/*** 显示从本地选择的图片* @param reader fileReader对象*/
Preview.prototype.show = function (reader) {var preView,img,me;preView = this.boxElem.find('#preview');img = preView.find('#preImg');me = this;if(img.length <= 0){preView.append($('<img id="preImg">'));}img = preView.find('#preImg');//确保图片加载完成后再执行回调img.on('load',function () {if(me.callback){me.callback(me.type);}});img.attr('src',reader.result);
};
/*** 是否支持预览* @returns {boolean}* @private*/
Preview.prototype.__isSupport = function () {return typeof FileReader === 'function';
};
var preview = new Preview();
module.exports = preview;

 

shear.js

var $ = require('jquery');
//由于要使用jquery-ui,所以将$暴露到window上。
window.$ = $;
require('./jquery-ui.min.js');
/*** 切割* @constructor*/
function Shear() {this.previewBox = null;this.cvsMove = null;this.maxW = 200;this.maxH = 200;this.thum = null;this.fileType = 'image/jpeg';
}
/*** 入口* @param previewBox 预览元素的父元素* @param fileType 裁剪的图片的类型 如:'image/jpg'* @returns {Shear}*/
Shear.prototype.start = function (previewBox,fileType) {if(!arguments.length) return this;var me = this;this.previewBox = previewBox;if(fileType){this.fileType = fileType;}this.thum = this.previewBox.find('#thum');this.cvsMove = this.previewBox.find('#cvsMove');this.showCanvas();return this;};
/*** 显示出canvas*/
Shear.prototype.showCanvas = function () {var preImg,h,w,me,cvsH,cvsW,rateH,rateW,naturalH,naturalW,preview;me = this;preImg = this.previewBox.find('#preImg');preview = this.previewBox.find('#preview');naturalH = preImg[0].naturalHeight;naturalW = preImg[0].naturalWidth;//将canvas显示出来this.cvsMove.show();//将canvas置于(0,0)this.cvsMove.css({"left":'0','top':'0'});h = preImg.height();w = preImg.width();//规定裁剪出的图片尺寸为200px*200px//要保证裁剪的图片不变形if(h < this.maxH || w < this.maxW){this.cvsMove[0].width = cvsW = Math.min(h,w);this.cvsMove[0].height = cvsH = Math.min(h,w);}else{this.cvsMove[0].width= cvsW = this.maxW;this.cvsMove[0].height= cvsH = this.maxH;}rateH = h/naturalH;rateW = w/naturalW;this.__drawImg(preImg,0,0,cvsW/rateW,cvsH/rateH,0,0,cvsW,cvsH);//使用jquery-ui中的功能使canvas可以移动this.cvsMove.draggable({containment: "parent",drag:function (event,ui) {var left,top;left = ui.position.left;top = ui.position.top;//canvas每次移动都有从新绘制图案me.__drawImg(preImg,left/rateW,top/rateH,cvsW/rateW,cvsH/rateH,0,0,cvsW,cvsH);}})
};
/*** 在canvas上显示图片* @param myImg 要显示的图片节点* @param sx 图片的起点在原图片上的x坐标* @param sy 图片的起点在原图上的y坐标* @param sW 在原图上的宽度* @param sH 在原图上的高度* @param dx 起点在canvas上的x坐标* @param dy 起点在canvas上的y坐标* @param dW 在canvas上的宽度* @param dH 在canvas上的高度* @private*/
Shear.prototype.__drawImg = function (myImg,sx,sy,sW,sH,dx,dy,dW,dH) {var cxt,thum,me;me = this;cxt = this.cvsMove[0].getContext('2d');cxt.drawImage(myImg[0],sx,sy,sW,sH,dx,dy,dW,dH);thum = this.thum;//将canvas上的图案显示到右侧
    thum.attr('src',this.cvsMove[0].toDataURL(me.fileType,1)).width(this.maxW).height(this.maxH)
};
var shear = new Shear();
module.exports = shear;

ajax.js

var $ = require('jquery');
function Ajax() {}
/*** 上传图片数据*/
Ajax.prototype.upload = function (data) {$.ajax({type:'POST',data:data,dataType:'json',url:'/test/PHP/upload.php',success:function (result) {if(result.status){location.reload();}else{alert(result.msg);}}});
};
var ajax = new Ajax();
module.exports = ajax;

 

最后在另一个文件中,调用customerImg对象的start方法

var $ = require('jquery');
var customerImg =require('./customerImg.js');
customerImg.start($('#warp'));

webpack的配置文件如下:

var webpack = require('webpack');
module.exports = {entry:{'customerImg':'./js/test.js','jQuery':['jquery']},output:{filename:'[name].js',library:'jQuery',libraryTarget:'umd'},plugins:[new webpack.optimize.CommonsChunkPlugin({name:'jQuery',filename:'jquery.js'})]
};

 效果:

4.php代码

if(!empty($_POST) && isset($_POST['customerImg'])){$img = $_POST['customerImg'];$imgdata = explode(',', $img);$uniName = md5 ( uniqid ( microtime ( true ), true ) );$a = file_put_contents('./../uploads/'.$uniName.'.jpg',  base64_decode($imgdata[1]));
}

 

转载于:https://www.cnblogs.com/QxQstar/p/6607039.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/469073.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

嵌入式就应该这样学!!

嵌入式就应该这样学&#xff01;&#xff01; 1、Linux内核 Linux 内核定时器 Linux进程上下文和中断上下文内核空间和用户空间 Linux内核链表 Linux 内核模块编译 Linux内核使用Gdb调试 Linux动态打印kernel日志 Linux的中断可以嵌套吗 Linux内核定时器 Linux 驱动之Ioctl Lin…

基于Springboot外卖系统02:数据库搭建+Maven仓库搭建

1 数据库环境搭建 1.1 创建数据库 可以通过以下两种方式中的任意一种, 来创建项目的数据库: 1).图形界面 注意: 本项目数据库的字符串, 选择 utf8mb4 2).命令行 1.2 数据库表导入 项目的数据库创建好了之后, 可以直接将 资料/数据模型/db_reggie.sql 直接导入到数据库中, …

margin 负边距应用

margin-right:负值&#xff0c;在没有设置DOM元素宽度的前提下&#xff0c;DOM元素宽度变宽。 1 <!DOCTYPE html>2 <html lang"zh-CN">3 4 <head>5 <meta charset"UTF-8">6 <meta http-equiv"X-UA-Co…

基于Springboot外卖系统03:pom.xml导入依赖+数据库配置文件+Boot启动类+静态资源映射

1).在pom.xml中导入依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache…

写给过得很辛苦很迷茫的你~一定要看啊

#前面的话 我是一个农村的孩子&#xff0c;我家很穷&#xff0c;小时候过得非常苦&#xff0c;每次开学是我最害怕的时候&#xff0c;我害怕我爸妈拿不出学费&#xff0c;我害怕我爸妈会让我辍学在家帮忙干活&#xff0c;每次跟我妈吵架的时候&#xff0c;当我妈跟我说不让我读…

flatpickr功能强大的日期时间选择器插件

flatpickr日期时间选择器支持移动手机&#xff0c;提供多种内置的主题效果&#xff0c;并且提供对中文的支持。它的特点还有&#xff1a; 使用SVG作为界面的图标。 兼容jQuery。 支持对各种日期格式的解析。 轻量级&#xff0c;高性能&#xff0c;压缩后的版本仅6K大小。 对…

基于Springboot外卖系统04:后台系统用户登录+登出功能

登录业务流程 ① 在登录页面输入用户名和密码 ② 调用后台接口进行验证 ③ 通过验证之后&#xff0c;根据后台的响应状态跳转到项目主页 2. 登录业务的相关技术点 http 是无状态的通过 cookie 在客户端记录状态通过 session 在服务器端记录状态通过 token 方式维持状态如果前端…

排序算法时间复杂度、空间复杂度、稳定性比较

排序算法分类 排序算法比较表格填空 排序算法平均时间复杂度最坏时间复杂度空间复杂度是否稳定冒泡排序:————-::—–::—–::—–:选择排序:————-::—–::—–::—–:直接插入排序:————-::—–::—–::—–:归并排序:————-::—–::—–::—–:快速排序:———…

基于Springboot外卖系统05:用户非登陆状态的页面拦截器实现

1. 完善登录功能 1.1 问题分析 用户访问接口验证&#xff0c;如果用户没有登录&#xff0c;则不让他访问除登录外的任何接口。 1.前端登录&#xff0c;后端创建session&#xff0c;返给前端 2.前端访问其他接口&#xff0c;失效或不存在&#xff0c;则返回失效提示&#xff…

python删除指定行_关于csv:删除python中的特定行和对应文件

我想删除90%的"转向"值等于0的行。这三个图像都有一个对应的图像文件&#xff0c;中间&#xff0c;左边和右边。我也要删除它们。csv文件如下&#xff1a;我编写了以下代码&#xff0c;以至少获取转向值为0的文件。我所需要的就是随机获取90%的文件并删除它们的代码。…

I2C总线传输协议

简介 I2C&#xff08;Inter-integrated Circuit&#xff09;总线支持设备之间的短距离通信&#xff0c;用于处理器和一些外围设备之间的接口&#xff0c;它只需要两根信号线来完成信息交换。I2C最早是飞利浦在1982年开发设计并用于自己的芯片上&#xff0c;一开始只允许100kHz…

基于Springboot外卖系统06: 新增员工功能+全局异常处理器

2. 新增员工 2.1 需求分析 后台系统中可以管理员工信息&#xff0c;通过新增员工来添加后台系统用户。点击[添加员工]按钮跳转到新增页面&#xff0c;如下 当填写完表单信息, 点击"保存"按钮后, 会提交该表单的数据到服务端, 在服务端中需要接受数据, 然后将数据保…

spring aop实现原理_Spring 异步实现原理与实战分享

最近因为全链路压测项目需要对用户自定义线程池 Bean 进行适配工作&#xff0c;我们知道全链路压测的核心思想是对流量压测进行标记&#xff0c;因此我们需要给压测的流量请求进行打标&#xff0c;并在链路中进行传递&#xff0c;那么问题来了&#xff0c;如果项目中使用了多线…

基于Springboot外卖系统07:员工分页查询+ 分页插件配置+分页代码实现

1. 员工分页查询 1.1 需求分析 在分页查询页面中, 以分页的方式来展示列表数据&#xff0c;以及查询条件 "员工姓名"。 请求参数 搜索条件&#xff1a; 员工姓名(模糊查询) 分页条件&#xff1a; 每页展示条数 &#xff0c; 页码 响应数据 总记录数 结果列表 1…

1045-Access denied for user 'root'@'localhost'(using password:YES)

解决&#xff1a; 1. 开始 --> cmd --> net stop mysql (停用MySQL服务 没启动的可以省略) 2. 找到安装路径 MySQL Server 5.1下的my.ini 3. 打开 my.ini 找到 [mysqld] 然后在下面加上 这句&#xff1a; skip_grant_tables &#xff08;意思好像是 启动MySQL服务…

arial字体可以商用吗_【工作总结】莫让字体版权引火上身

前段一条微软雅黑字体引发的巨额罚款新闻&#xff0c;引起国内多个TW大群小地震&#xff0c;人人自危。我也赶紧检查自家文档、商用出版物、网站的字体&#xff0c;以免给公司带来法务后患。把这两天收集的信息&#xff0c;采取的行动记录一下。哪些中文字体免费&#xff1f;事…

基于Springboot外卖系统08:员工账号状态管理功能+对象转换器+扩展Spring mvc的消息转换器

1. 员工账号状态管理 1.1 需求分析 在员工管理列表页面&#xff0c;可以对某个员工账号进行启用或者禁用操作。账号禁用的员工不能登录系统&#xff0c;启用后的员工可以正常登录。如果某个员工账号状态为正常&#xff0c;则按钮显示为 "禁用"&#xff0c;如果员工…

基于Springboot外卖系统09:员工信息编辑+员工信息保存

1 编辑员工信息功能 1.1 需求分析 在员工管理列表页面点击 "编辑" 按钮&#xff0c;跳转到编辑页面&#xff0c;在编辑页面回显员工信息并进行修改&#xff0c;最后点击 "保存" 按钮完成编辑操作。 那么从上述的分析中&#xff0c;当前实现的编辑功能需…

bcp 不能调用where 子句_MySQL中IS NULL、IS NOT NULL、!=不能用索引?胡扯!

不知道从什么时候开始&#xff0c;网上流传着这么一个说法&#xff1a;MySQL的WHERE子句中包含 IS NULL、IS NOT NULL、! 这些条件时便不能使用索引查询&#xff0c;只能使用全表扫描。这种说法愈演愈烈&#xff0c;甚至被很多同学奉为真理。咱啥话也不说&#xff0c;举个例子。…

基于Springboot外卖系统10:公共字段填充功能+ThreadLocal模块改进

1. 公共字段自动填充 1.1 问题分析 在新增员工时需要设置创建时间、创建人、修改时间、修改人等字段&#xff0c;在编辑员工时需要设置修改时间、修改人等字段。这些字段属于公共字段&#xff0c;也就是也就是在系统中很多表中都会有这些字段&#xff0c;如下&#xff1a; 而…