隐藏

移动网页html5的canvas画布生成缩略图的方法

发布:2016/1/17 14:05:58作者:管理员 来源:本站 浏览次数:1972

本文来讲讲移动端html5的canvas画布生成缩略图的方法,手机端的网站已经是趋势,而且现在网速也很快,打开图片分分钟,所以我们没有必要用后端生成物理图片了。

公司的移动页面, 上传图片时缩略图是靠后端生成, 但是随着现在的手机越来越牛X(摄像头比数码相机还厉害~), 图片体积也越来越大.

一个几M的图, 也许我们只是用来生成一个100*100的小图, 上传到后端再生成缩略图就大大的浪费了, 而且提交表单的等待时间也非长久, 对用户体验也不好.

普通的web表单, 上传图片靠后端来生成缩略图很平常, 但有了HTML5, 针对移动Web开发可以考虑使用前端生成缩略图了.

写了个生成缩略图的jquery的插件, 主要参数:

width: 生成缩略图的宽; height: 生成缩略图的高;
    fill: 图片小于缩略图尺寸时, 是否填充(false: 缩略图宽高自动缩放到适应图片, true: 缩略图尺寸不变)
    background:生成图片填充背景(默认#fff, 设置null时, 背景透明)
    type: 生成图片类型 ('image/jpeg' 或 'image/png')
    size: 生成缩略图方式, 生成缩略图的效果主要参考了CSS3的background-size属性:
      contain: 等比缩放并拉伸, 图片全部显示;
      cover: 等比缩放并拉伸, 图片把容器完全覆盖;
      auto: 图片不拉伸, 居中显示.
    mark: 水印
      文字水印: mark = {padding: 5, height: 18, text: 'test', color: '#000', font: '400 18px Arial'}
      图片水印: mark = {padding: 5, src: 'mark.png', width: 34, height: 45};
    stretch: 小图是否强制拉伸以适应缩略图的尺寸(size = auto/contain时)
    success: 生成缩略图后 callback

大体思路如下:

首先判断是否支持fileReader(支持fileReader, canvas就不在话下了)

不支持的话: 不做任何操作, 默认的input type="file"上传, 靠后端生成缩略图.

支持的情况: input change时, 判断选择的文件是图片, 就创建一个隐藏的canvas, 并把图片画到canvas里,

因为要生成缩略图, 所以在canvas里画图的时候, 控制剪切坐标和被剪切的宽高就OK了.

另外可以加上水印, 图片水印或者文字水印加到canvas上面也是比较方便的.

最后 canvas.toDataURL 转成base64, post到后端(先把input type="file"移除, 再生成个新的input type="hidden"储存图片数据), 后端接收后直接保存为图片就OK了.

主要用到: FileReader和canvas, 一个用来读取本地图片, 一个用来生成缩略图.

做移动网页开发的同学可以考虑下.


实例:

html5页面

<h2>html5</h2>
<script src="/js/jquery-2.1.4.min.js"></script>
<link href="/css/base.css" rel="stylesheet" />
<script src="/js/ImgUpload.js"></script>
<script>
    $(function () {
       new H5ImgUpload.init("imgUpload", "myCanvas", 400);
        $("#uploadimg").click(function () {
            H5ImgUpload.sendImage("myCanvas", "/Test/WxImg/uploadimg");
        });
       new H5ImgUpload.init("imgUpload1", "myCanvas1", 200);
        $("#uploadimg1").click(function () {
            H5ImgUpload.sendImage("myCanvas1", "/Test/WxImg/uploadimg");
        });
        $("#uploadAllImg").click(function () {
            H5ImgUpload.uploadAllImage(".Canvas", "/Test/WxImg/uploadAllImg");
        });
    });
</script>
<a class="addphoto">
<input type="file" id="imgUpload" class="imgUpload" name="file1" draggable="false" single accept="image/*">
    </a>
<canvas id="myCanvas" class="Canvas" data-id="img1" style="width:150px;"></canvas>
<input type="button" id="uploadimg" value="上传" />
<div style="clear:both;"></div><br>
<a class="addphoto">
<input type="file" id="imgUpload1" class="imgUpload" name="file2" draggable="false" single accept="image/*">
    </a>
<canvas id="myCanvas1" class="Canvas" data-id="img2"  style="width:150px;"></canvas>
<input type="button" id="uploadimg1" value="上传" />

<br/>
<input type="button" id="uploadAllImg" value="上传所有图片" />


imageUpload.js

var MAX_HEIGHT = 300;
var H5ImgUpload = {
    //obj=上传控件
    //objCanvas=画布控件
    //maxHeight=图片最大高度(像素)
    init: function (obj, objCanvas, maxHeight) {
        if (maxHeight <= 0)
            maxHeight = MAX_HEIGHT;
        //判断浏览器是否有FileReader接口
        if (typeof FileReader == 'undefined') {
            //alert("亲,您的浏览器无法使用图片本地预览");
            //如果浏览器是ie
            if ($.browser.msie === true) {
                H5ImgUpload.render(objCanvas, $("#" + obj).val(), maxHeight);
            }
                //如果是不支持FileReader接口的低版本firefox 可以用getAsDataURL接口
            else if ($.browser.mozilla === true) {
                H5ImgUpload.render(objCanvas, $("#" + obj).val(), maxHeight);
            }
        } else {//支持FileReader接口 
            //showPicture(obj);
            H5ImgUpload.showPicture(obj, objCanvas, maxHeight);


        }
    },
    showPicture: function (obj, objCanvas, maxHeight) {
        $("#" + obj).change(
            function (e) {
                for (var i = 0; i < e.target.files.length; i++) {
                    var file = e.target.files.item(i);
                    //允许文件MIME类型 也可以在input标签中指定accept属性
                    //console.log(/^image\/.*$/i.test(file.type));
                    if (!(/^image\/.*$/i.test(file.type))) {
                        continue; //不是图片 就跳出这一次循环
                    }
                    //实例化FileReader API
                    var freader = new FileReader();
                    freader.readAsDataURL(file);
                    freader.onload = function (e) {
                        H5ImgUpload.render(objCanvas, e.target.result, maxHeight);
                    }
                }
            });
    },
    render: function (objCanvas, src, maxHeight) {
        // 创建一个 Image 对象
        var image = new Image();
        // 绑定 load 事件处理器,加载完成后执行
        image.onload = function () {
            // 获取 canvas DOM 对象
            var canvas = document.getElementById(objCanvas);
            // 如果高度超标
            if (image.height > maxHeight) {
                // 宽度等比例缩放 *=
                image.width *= maxHeight / image.height;
                image.height = maxHeight;
            }
            // 获取 canvas的 2d 环境对象,
            // 可以理解Context是管理员,canvas是房子
            var ctx = canvas.getContext("2d");
            // canvas清屏
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            // 重置canvas宽高
            canvas.width = image.width;
            canvas.height = image.height;
            // 将图像绘制到canvas上
            ctx.drawImage(image, 0, 0, image.width, image.height);
            // !!! 注意,image 没有加入到 dom之中
        };
        // 设置src属性,浏览器会自动加载。
        // 记住必须先绑定事件,才能设置src属性,否则会出同步问题。
        image.src = src;
    },
    sendImage: function (objCanvas, url) {
        // 获取 canvas DOM 对象
        var canvas = document.getElementById(objCanvas);
        // 获取Base64编码后的图像数据,格式是字符串
        // "data:image/png;base64,"开头,需要在客户端或者服务器端将其去掉,后面的部分可以直接写入文件。
        var dataurl = canvas.toDataURL("image/png");
        // 为安全 对URI进行编码
        // data%3Aimage%2Fpng%3Bbase64%2C 开头
        var imagedata = encodeURIComponent(dataurl);
        var data = {
            img64: imagedata
        };
        jQuery.ajax({
            url: url,
            data: data,
            type: "POST",
            // 期待的返回值类型
            dataType: "json",
            complete: function (xhr, result) {
                if (result == 'timeout') {//超时,status还有success,error等值的情况
                    //ajaxTimeoutTest.abort();
                    alert("超时");
                } else {
                    alert(xhr.responseText);
                }
            }
        });
    },
    uploadAllImage: function (classCanvas, url) {
        var arrayObj = new Array(); //创建一个数组
        jQuery(classCanvas).each(function () {
            var dataurl = this.toDataURL("image/png");
            var obj = new Object();
            obj.name = jQuery(this).attr("data-id");
            obj.value = encodeURIComponent(dataurl);
            arrayObj.push(obj);
        });
        var data = {
            objImg64: JSON.stringify(arrayObj)
        };
        jQuery.ajax({
            url: url,
            data: data,
            type: "POST",
            // 期待的返回值类型
            dataType: "json",
            complete: function (xhr, result) {
                alert(xhr.responseText);
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                if (textStatus == "timeout")
                {
                    alert("超时");
                } else if (textStatus == "error")
                {
                    alert(errorThrown);
                }
            }


        });
    }


};


后端控制器:

[HttpPost]
        public JsonResult uploadAllImg()
        {
            string base64 = Server.UrlDecode(Request.Form["objImg64"]);// Request.Form["img64"].Replace("data:image/png;base64,", "");
            JavaScriptSerializer js = new JavaScriptSerializer();
            List<uploadImg> jg = js.Deserialize<List<uploadImg>>(base64);
            string a1 = "";
            string a2 = "";
            foreach (var s in jg)
            {
                if (s.name == "img1")
                {
                    a1 = s.name;
                }
                var _base64 = s.value.Replace("data:image/png;base64,", "");
                byte[] arr = Convert.FromBase64String(_base64);
                using (MemoryStream ms = new MemoryStream(arr))
                {
                    using (Bitmap bmp = new Bitmap(ms))
                    {
                        bmp.Save(Server.MapPath("/") + "upload/img/" + NetProjectCommon.Utils.GetRamCode() + ".jpg", ImageFormat.Jpeg);
                    }
                }
            }
          
            return Json(1);
        }