问题描述

手机端会员中心头像上传是个基本的功能需求,目前手机照片像素越来越大,有的甚至超过10M,对于普通的PHP主机来说,不特殊配置根本无法上传,如何通过手机端浏览器自带的api进行上传前缩放,是解决这个问题的有效方法

浏览器接口

利用FileReader对象读取上传文件,然后通过canvas缩放,转成base64字符上传,头像的尺寸不要太大,宽度400像素足够用,这样一张超大图片压缩后才60KB左右,非常节省带宽。

思路描述

  • 创建上传按钮,上传按钮做成绝对定位,透明色
  • 创建图片处理临时容器,这个容器尽量不可见,绝对定位,放到可视范围以外
  • 服务端用PHP对base64进行解码

    实现代码

    html容器代码

<div class="img" style="position: relative">
<input type="file" onchange="fileSelected(this);" accept="image/*" style="position: absolute;width: 100%;height: 100%;z-index: 999;opacity: 0;">
<img class="avatar" style="width: 80px;height: auto;" src="./images/img_user.png"/>
</div>

<div id="image-tmp-div" style="position:absolute;opacity: 0;width: 400px;overflow: hidden;left: -400px;">
    <img src="" id="image-tmp"/>
    <canvas id="canvas-tmp"/>
</div>

javascript代码

    function fileSelected(obj) {
        var MAX_WIDTH = 400;
        var oFile = obj.files[0];
        var oImage = document.getElementById('image-tmp');
        // prepare HTML5 FileReader
        var canvas = document.getElementById("canvas-tmp");
        var oReader = new FileReader();
        oReader.onload = function (e) {
            oImage.src = e.target.result;
            oImage.src = "data:application/octet-stream;" + e.target.result.substr(e.target.result.indexOf("base64,"));
            oImage.onload = function () { // binding onload event
                if (oImage.width > MAX_WIDTH) {
                    // 宽度等比例缩放 *=
                    oImage.width = MAX_WIDTH;
                    oImage.height *= MAX_WIDTH / oImage.width;
                }
                var ctx = canvas.getContext("2d");
                ctx.clearRect(0, 0, canvas.width, canvas.height);
                canvas.width = oImage.width;
                canvas.height = oImage.height;
                ctx.drawImage(oImage, 0, 0, oImage.width, oImage.height);
                var picData = canvas.toDataURL("image/png");
                $.ajax({
                    type: "POST",
                    url: "{:url('upload')}",
                    data: {"img_data": picData},
                    success: function (r) {
                        if (r.code !== 1) {
                            alert(r.msg);
                            return;
                        }
                        $('.avatar').attr("src", "{:UPLOAD_PATH}" + r.url + "?" + Math.random());
                    },
                    error: function (err) {
                        alert('操作失败,请联系管理员');
                    }
                });
            };
            oImage.onerror = function () {
                alert('没有缩略图,请返回重试');
            }
        };
        oReader.readAsDataURL(oFile);
    }

php代码

class Upload {
public function idpath($id) {
        $id = abs(intval($id));
        $id = sprintf("%09d", $id);
        $dir1 = substr($id, 0, 3);
        $dir2 = substr($id, 3, 2);
        $dir3 = substr($id, 5, 2);
        return $dir1 . '/' . $dir2 . '/' . $dir3 . '/';
    }

    public function bybase64($imgid, $dir, $base64_str) {
        $dest_dir = UPLOAD_ROOT . $dir . '/' . $this->idpath($imgid);
        ac('file::mkdir', $dest_dir);
        list($ext, $tmp) = explode(';base64,', $base64_str);
        if (empty($tmp)) {
            return array('url' => '');
        }
        $ext = 'jpg';
        $targetFile = $dest_dir . $imgid . '.' . $ext;
        //用string读取
        $tmp = imagecreatefromstring(base64_decode($tmp));
        $w = imagesx($tmp);
        $h = imagesy($tmp);
        $simg = imagecreatetruecolor($w, $h);
        $bg = imagecolorallocate($simg, 255, 255, 255);
        imagefill($simg, 0, 0, $bg);
        imagecopyresized($simg, $tmp, 0, 0, 0, 0, $w, $h, $w, $h);
        imagejpeg($simg, $targetFile, 80);
        imagedestroy($simg);
        $ret = array('url' => substr($targetFile, strlen(UPLOAD_ROOT)));
        $ret['width'] = $w;
        $ret['height'] = $h;
        return $ret;
    }
}

 // ProfileController.php控制器
  public function uploadAction(Request $request) {
        $img = $request->post("img_data");
        if ($img) {
            $data = ac('upload::bybase64', $this->user_id, "avatar", $img);
            if ($data) {
                $data['code'] = 1;
                User::where('id', $this->user_id)->update(['avatar' => $data['url']]);
                ajax_return($data);
            }
        } else {
            $this->error("图片不能为空");
        }
    }

标签: none

评论已关闭