HTML5 图片本地压缩上传插件
======================前端代码========================= <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>localResizeIMG</title> <!--引入JQuery 用于异步上传图片--> <script type="text/javascript" src="dist/jquery-3.1.1.min.js"></script> <!--引入 lrz 插件 用于压缩图片--> <script type="text/javascript" src="dist/lrz.bundle.js"></script> </head> <body> <input type="file" accept="image/jpeg" capture="camera"> </body> <script> $("input[type=file]").change(function () { /* 压缩图片 */ lrz(this.files[0], { width: 300 //设置压缩参数 }).then(function (rst) { /* 处理成功后执行 */ rst.formData.append('base64img', rst.base64); // 添加额外参数 $.ajax({ url: "upload.php", type: "POST", data: rst.formData, processData: false, contentType: false, success: function (data) { $("<img />").attr("src", data).appendTo("body"); } }); }).catch(function (err) { /* 处理失败后执行 */ }).always(function () { /* 必然执行 */ }) }) </script> </html> 引入插件:<script type="text/javascript" src="dist/lrz.bundle.js"></script> 绑定事件:$("input[type=file]").change(function () {/* 压缩上传处理 */}); 压缩图片:lrz(file, [options]); file 通过 input:file 得到的文件,或者直接传入图片路径 [options] 这个参数允许忽略 width {Number} 图片最大不超过的宽度,默认为原图宽度,高度不设定时会适应宽度 height {Number} 图片的最大高度,默认为原图高度 quality {Number} 图片压缩质量,取值 0 - 1,默认为 0.7 fieldName {String} 后端接收的字段名,默认:file 返回结果:promise 对象 then(rst) 处理成功后执行 rst.formData 后端可处理的数据 rst.file 压缩后的file对象,如果压缩率太低,将会是原始file对象 rst.fileLen 生成后的图片的大小,后端可以通过此值来校验是否传输完整 rst.base64 生成后的图片base64,后端可以处理此字符串为图片,也可以直接用于 img.src = base64 rst.base64Len 生成后的base64的大小,后端可以通过此值来校验是否传输完整 rst.origin 也就是原始的file对象,里面存放了一些原始文件的信息,例如大小、日期等 异步上传:processData 和 contentType 必须设为 false,否则服务端不会响应 ======================后端代码========================= <?php $base64_image_content = $_POST['base64img']; $output_directory = './image'; //设置图片存放路径 /* 检查并创建图片存放目录 */ if (!file_exists($output_directory)) { mkdir($output_directory, 0777); } /* 根据base64编码获取图片类型 */ if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $base64_image_content, $result)) { $image_type = $result[2]; //data:image/jpeg;base64, $output_file = $output_directory . '/' . md5(time()) . '.' . $image_type; } /* 将base64编码转换为图片编码写入文件 */ $image_binary = base64_decode(str_replace($result[1], '', $base64_image_content)); if (file_put_contents($output_file, $image_binary)) { echo $output_file; //写入成功输出图片路径 }
/* * LUploader图片压缩上传插件 * * 作者:黄磊 * * 报告漏洞,意见或建议, 请联系邮箱:xfhxbb@yeah.net * * 创建于:2016年3月16日 * * Copyright 2016 * * 获得使用本类库的许可, 您必须保留著作权声明信息。 * */ (function() { window.LUploader = function(el, params) { var _self = this; _self.trigger=el; _self.params = { accept: 'image/*', multiple: false, maxsize: 102400, imgObj: {}, showsize: false, quality:0.1, url: '' } for (var param in params) { _self.params[param] = params[param]; } _self.init(); }; LUploader.prototype.init = function() { var _self = this; _self.trigger.setAttribute('accept', _self.params.accept); _self.params.multiple && _self.trigger.setAttribute('multiple', ''); var btn = document.querySelector('#' + _self.trigger.getAttribute('data-LUploader')); btn.addEventListener('click', function() { _self.trigger.click(); }); _self.trigger.addEventListener('change', function() { if (!this.files.length) return; var files = Array.prototype.slice.call(this.files); files.forEach(function(file, i) { if (!/\/(?:jpeg|png|gif)/i.test(file.type)) return; var reader = new FileReader(); _self.params.imgObj.size = file.size / 1024 > 1024 ? (~~(10 * file.size / 1024 / 1024)) / 10 + "MB" : ~~(file.size / 1024) + "KB"; var li = document.createElement("li"); li.innerHTML = '<div class="LUploader-progress"><span></span><input type="hidden" value="" /></div>'; if (_self.params.showsize) { var div_size = document.createElement('div'); div_size.className = 'LUploader-size'; div_size.textContent = _self.params.imgObj.size; li.appendChild(div_size); } var LUploaderList = _self.trigger.parentElement.querySelector('.LUploader-list'); if (!_self.params.multiple) { //假如是单个上传 if (_self.old_li) { LUploaderList.removeChild(_self.old_li); } else { _self.old_li = li; } } LUploaderList.appendChild(li); LUploaderList.parentElement.nextElementSibling.style['display'] = 'none'; reader.onload = function() { var params = dataSet(_self.trigger); var url = _self.params.url; var result = this.result; var img = new Image(); _self.params.imgObj.src = img.src = result; li.style['background-image'] = 'url(' + result + ')'; if (result.length <= _self.params.maxsize) { img = null; _self.upload(url, params, result, file.type, li); return; } if (img.complete) { callback(); } else { img.onload = callback; } function callback() { var data = _self.compress(img); _self.upload(url, params, data, file.type, li); img = null; } }; reader.readAsDataURL(file); }); }); }; LUploader.prototype.compress = function(img) { var canvas = document.createElement("canvas"); var ctx = canvas.getContext('2d'); var moreCanvas = document.createElement("canvas"); var morectx = moreCanvas.getContext("2d"); var maxsize = 100 * 1024; var width = img.width; var height = img.height; var ratio; if ((ratio = width * height / 4000000) > 1) { ratio = Math.sqrt(ratio); width /= ratio; height /= ratio; } else { ratio = 1; } canvas.width = width; canvas.height = height; ctx.fillStyle = "#fff"; ctx.fillRect(0, 0, canvas.width, canvas.height); var count; if ((count = width * height / 1000000) > 1) { count = ~~(Math.sqrt(count) + 1); var nw = ~~(width / count); var nh = ~~(height / count); moreCanvas.width = nw; moreCanvas.height = nh; for (var i = 0; i < count; i++) { for (var j = 0; j < count; j++) { morectx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh); ctx.drawImage(moreCanvas, i * nw, j * nh, nw, nh); } } } else { ctx.drawImage(img, 0, 0, width, height); } var ndata = canvas.toDataURL('image/jpeg', this.params.quality); moreCanvas.width = moreCanvas.height = canvas.width = canvas.height = 0; return ndata; }; LUploader.prototype.upload = function(url, obj, basestr, type, li) { var text = window.atob(basestr.split(",")[1]); var buffer = new Uint8Array(text.length); var pecent = 0; for (var i = 0; i < text.length; i++) { buffer[i] = text.charCodeAt(i); } var span = li.querySelector('.LUploader-progress').querySelector('span'); var hidden_input = li.querySelector('.LUploader-progress').querySelector('input'); var xhr = new XMLHttpRequest(); xhr.open('post', url); xhr.onload = function(e) { if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 0) { var data = JSON.parse(xhr.responseText); var result = data['status']; var text = result == 0 ? '上传成功' : '上传失败'; span.style['width'] = '100%'; span.innerHTML = text; hidden_input.value = data['path']; } else { span.innerHTML = '上传失败'; } } xhr.upload.addEventListener('progress', function(e) { pecent = ~~(100 * e.loaded / e.total); span.style['width'] = pecent + '%'; span.innerHTML = (pecent == 100 ? 99 : pecent) + '%'; }, false); var data = {}; for (var key in obj) { if (key !== 'luploader') { if (obj[key] == 'basestr') { data[key] = basestr; } else { data[key] = obj[key]; } } }; data = serializeObject(data); xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded; charset=UTF-8'); xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); xhr.send(data); } function isArray(arr) { if (Object.prototype.toString.apply(arr) === '[object Array]') return true; else return false; }; function serializeObject(obj) { if (typeof obj === 'string') return obj; var resultArray = []; var separator = '&'; for (var prop in obj) { if (obj.hasOwnProperty(prop)) { if (isArray(obj[prop])) { var toPush = []; for (var i = 0; i < obj[prop].length; i++) { toPush.push(encodeURIComponent(prop) + '=' + encodeURIComponent(obj[prop][i])); } if (toPush.length > 0) resultArray.push(toPush.join(separator)); } else { resultArray.push(encodeURIComponent(prop) + '=' + encodeURIComponent(obj[prop])); } } } return resultArray.join(separator); }; function dataSet(el) { var dataset = {}; for (var i = 0; i < el.attributes.length; i++) { var attr = el.attributes[i]; if (attr.name.indexOf('data-') >= 0) { dataset[toCamelCase(attr.name.split('data-')[1])] = attr.value; } } return dataset; } function toCamelCase(string) { return string.toLowerCase().replace(/-(.)/g, function(match, group1) { return group1.toUpperCase(); }); }; })(); <!doctype html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="Access-Control-Allow-Origin" content="*"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui"> <meta content="yes" name="apple-mobile-web-app-capable"> <meta content="black" name="apple-mobile-web-app-status-bar-style"> <meta content="telephone=no" name="format-detection"> <meta content="email=no" name="format-detection"> <title>移动端图片压缩上传</title> <link rel="stylesheet" href="css/LUploader.css"> <style> * { margin: 0; padding: 0; } h1{ background-color: #19b5ee; color: #fff; font-size: 25px; text-align: center; padding: 10px; } li { list-style-type: none; } input { outline: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } </style> </head> <body> <h1>LUploader移动端图片压缩上传</h1> <div class="LUploader" id="demo1"> <div class="LUploader-container"> <input data-LUploader='demo1' data-form-file='basestr' data-upload-type='front' type="file" /> <ul class="LUploader-list"></ul> </div> <div> <div class="icon icon-camera font20"></div> <p>单击上传</p> </div> </div> <script src="js/LUploader.js?r=<?php echo time();?>"></script> <script> [].slice.call(document.querySelectorAll('input[data-LUploader]')).forEach(function(el) { new LUploader(el, { url: './upload.php',//post请求地址 multiple: false,//是否一次上传多个文件 默认false maxsize: 102400,//忽略压缩操作的文件体积上限 默认100kb accept: 'image/*',//可上传的图片类型 quality: 0.5,//压缩比 默认0.1 范围0.1-1.0 越小压缩率越大 showsize:true//是否显示原始文件大小 默认false }); }); </script> </body> </html>