文章目录
- 场景
- 原因
- 解决方案
- 完整的代码
- 前端代码
- php代码
场景
我有个需求,移动端h5上传多张的图片。用input file可以上传多张,但是现在照片体积越来越大,同时上传多张会因为体积过大,导致上传失败。如果是小程序会好很多,可以直接先压缩在上传,已经提供的功能。h5上没提供,只能自己解决了。
原因
自己用js canvas先压缩图片再上传,这时候上传的就是图片的base64编码。php接受后存储为图片。但是有的图片保存没问题,有的图片一部分成了灰色块。如下图
经过查找,有的说是因为base64的头部信息,不是这个问题,因为我保存的时候已经去掉了。
再找,发现ajax在传输过程中加号会变成空格而base64里是有加号的,所以在ajax传输前先要对base64进行编码,把加号替换成%2B的url编码。也就是说,ajax在传输过程中修改了图片的base64编码,导致图片解析失败,解析不出来就变成灰色了。
解决方案
先用js对图片的base64编码进行url编码
imgBase64_2=encodeURIComponent(imgBase64);
php接受后先解码,然后再保存为图片
$base64_image_content=$_POST['image'];
$base64_image_content=urldecode($base64_image_content);
完整的代码
前端代码
前端代码没有做提交功能,数据已经存放在隐藏域 image[]里了。用form表单或者ajax提交都可以。这个可以自己实现。
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><meta name="viewport"content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /><title></title><style>.upload-file {position: relative;width: 100px;height: 100px;order: 9;background-color: grey;}#file {width: 100%;height: 100%;opacity: 0;}.upload_Picitem{width: 150px;height: 150px;}.upload_Picitem img{width: 150px;height: 150px;}</style></head>
<body>
<section class="upload-section"><article class="upload-piclist" id="upload-piclist"><div id="image_container"></div><div class="upload-file"><input type="file" id="file" accept="image/*" multiple onchange="imgChange()" /></div></article>
</section>
<button id='subBtn'>提交</button>
<script src="https://www.jq22.com/jquery/jquery-1.10.2.js"></script>
<script>function imgChange() {let file =document.getElementById('file').files;let filelist = file.length ;for (let i = 0; i < filelist; i++) {readerfile(file[i]).then(e => {// 对生成的base64照片进行压缩// 第一个参数就是需要压缩的base64// 第二个是压缩系数 0-1,// 第三个压缩后的回调 用来获取压缩处理后的 base64compressImg(e,buildImgDiv);})}}function compressImg (base64,callback) {// 第一个参数就是需要加密的base64,// 第二个是压缩系数 0-1,// 第三个压缩后的回调 用来获取处理后的 base64if (!base64) {return}// 压缩方法let newImage = new Image()let quality = 0.9 // 压缩系数0-1之间newImage.src = base64//newImage.setAttribute('crossOrigin', 'Anonymous') // url为外域时需要let imgWidth, imgHeightlet w = undefinednewImage.onload = function () {// 这里面的 this 指向 newImage// 通过改变图片宽高来实现压缩w = 800imgWidth = this.widthimgHeight = this.heightlet canvas = document.createElement('canvas')let ctx = canvas.getContext('2d')if (imgWidth > w) {canvas.width = w// 等比例缩小canvas.height = w * (imgHeight / imgWidth)} else {canvas.width = imgWidthcanvas.height = imgHeight}ctx.clearRect(0, 0, canvas.width, canvas.height)ctx.drawImage(this, 0, 0, canvas.width, canvas.height) // // 这里面的 this 指向 newImagelet smallBase64 = canvas.toDataURL('image/jpeg', quality) // 压缩语句callback(smallBase64)}}// 压缩完成后的回调函数,接收压缩后的base64function buildImgDiv(imgBase64){var it='<div class="upload_Picitem"><img src=' + imgBase64 + ' /><input type="hidden" name="image[]" value="'+imgBase64+'" /><span class="closeClass"></span></div>'$('#image_container').append(it)}function readerfile(file) {return new Promise((resolve, reject) => {let reader = new FileReader();reader.addEventListener("load", function() {resolve(reader.result);}, false)if (file) {reader.readAsDataURL(file)}})}
</script></body>
</html>
php代码
function saveBase64($base64_image_content){$base64_image_content=urldecode($base64_image_content);if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $base64_image_content, $result)){//图片后缀$type = $result[2];//保存位置--图片名$image_name=date('YmdHis').str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT).".".$type;$imge_web_url='/Uploads/chuchai/'.$image_name;$imge_real_url = ROOT_PATH.$imge_web_url;//解码$decode=base64_decode(str_replace($result[1], '', $base64_image_content));if (file_put_contents($imge_real_url, $decode)){$data['code']=200;$data['url']=$imge_web_url;$data['msg']='保存成功!';return $data;}else{$data['code']=0;$data['url']='';$data['msg']='图片保存失败!';return $data;}}else{$data['code']=2;$data['imgageName']='';$data['url']='';$data['msg']='base64图片格式有误!';return $data;}
}