用Canvas+Javascript FileAPI 实现一个跨平台的图片剪切、滤镜处理、上传下载工具(转)

直接上代码,其中上传功能需要自己配置允许跨域的文件服务器地址~

或者将html文件贴到您的站点下同源上传也OK。

支持:

不同尺寸图片获取、

原图缩小放大、

原图移动、

选择框大小改变、

下载选中的区域、

上传选中的区域、

几种简单的滤镜(自己添加滤镜函数即可添加滤镜效果)

 

移动端适配要点

① 替换事件名称

if(/^.*(Android|iPad|iPhone){1}.*$/.test(navigator.userAgent)){
eventName={down:"touchstart",move:"touchmove",up:"touchend",click:"tap"};
}

② 移动端touch事件e没有clientX属性,需要做如下处理

//处理事件,支持移动端
//e.originalEvent.targetTouches[0].pageX
function dealE(e){
e.clientX= e.clientX || e.originalEvent.targetTouches[0].clientX;
e.clientY= e.clientY || e.originalEvent.targetTouches[0].clientY;
}

③ 移动端浏览器展示网页在手指拖动的过程中是会左右晃悠的,体验十分不好。

给所有事件都加上

e.preventDefault();

④ 移动端浏览器对File上传支持不好,微信甚至干脆屏蔽了File上传请求

我的做法是:

获取图片文件的base64字符串:

 var imgData = $("#res1")[0].toDataURL("png");
        imgData = imgData.replace(/^data:image\/(png|jpg);base64,/, "");

 

然后自己在后端实现一个文件上传代理,接收base64字符串,拼接body:

 proxyRequest.ContentType = "multipart/form-data; boundary=----WebKitFormBoundaryqwqoxnDz0J0XB2Ti";
        StreamReader reader = new StreamReader(_context.Request.InputStream);
        string base64=reader.ReadToEnd();
        string divider = "----WebKitFormBoundaryqwqoxnDz0J0XB2Ti";
        string content = "";
        content += "--"+divider;
        content += "\r\n";
        content += "Content-Disposition: form-data; name=\"userlogo\"; filename=\"userlogo.png\"";
        content += "\r\n";
        content += "Content-Type: image/png";
        content += "\r\n\r\n";
        byte[] bytes1 = Encoding.UTF8.GetBytes(content);
        byte[] bytes2 = Convert.FromBase64String(base64);
        byte[] bytes3 = Encoding.UTF8.GetBytes("\r\n" + "--" + divider + "--\r\n");
        byte[] bytes = new byte[bytes1.Length+bytes2.Length+bytes3.Length];
        bytes1.CopyTo(bytes,0);
        bytes2.CopyTo(bytes, bytes1.Length);
        bytes3.CopyTo(bytes, bytes1.Length + bytes2.Length);
        proxyRequest.ContentLength = bytes.Length;

这样对于移动端浏览器来说这就是一个普通的请求。

至此,移动端完美支持!

 

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>get image</title>
<style>
    canvas{
        border:solid thin #ccc;
        cursor:pointer;
    }
    #canvasContainer{
        position:relative;
    }
    #picker{
        position:absolute;
        border:solid thin #ccc;
        cursor: move;
        overflow:hidden;
        z-index:2;
    }
    #resize{
         width: 0;
         height: 0;
         border-bottom: 15px solid rgba(200,200,200,0.8);
         border-left: 15px solid transparent;
         right: 0;
         bottom: 0;
         position: absolute;
         cursor: se-resize;
         z-index:3;
    }
</style>
<script src="http://libs.baidu.com/jquery/1.9.0/jquery.js"></script>
<script>
    $(function(){
        var canvas=document.getElementById("container"),
            context=canvas.getContext("2d"),
            //文件服务器地址
            fileServer=null,
            //适配环境,随时修改事件名称
            eventName={down:"mousedown",move:"mousemove",up:"mouseup",click:"click"};
        //////////canvas尺寸配置
        var canvasConfig={
                //容器canvas尺寸
                width:500,
                height:300,
                //原图放大/缩小
                zoom:1,
                //图片对象
                img:null,
                //图片完整显示在canvas容器内的尺寸
                size:null,
                //图片绘制偏移,为了原图不移出框外,这个只能是负值or 0
                offset:{x:0,y:0},
                //当前应用的滤镜
                filter:null
        }
        canvas.width=canvasConfig.width;
        canvas.height=canvasConfig.height;
        ///////////设置选择工具配置
        var config={
            //图片选择框当前大小、最大大小、最小大小
            pickerSize:100,
            minSize:50,
            maxSize:200,
            x:canvas.width/2-100/2,
            y:canvas.height/2-100/2
        }
        /////////////结果canvas配置
        var resCanvas=[$("#res1")[0].getContext("2d"),$("#res2")[0].getContext("2d"),$("#res3")[0].getContext("2d")];
        //结果canvas尺寸配置
        var resSize=[100,50,32]
        resSize.forEach(function(size,i){
            $("#res"+(i+1))[0].width=size;
            $("#res"+(i+1))[0].height=size;
        });
        //////// 滤镜配置
        var filters=[];
        filters.push({name:"灰度",func:function(pixelData){
            //r、g、b、a
            //灰度滤镜公式: gray=r*0.3+g*0.59+b*0.11
            var gray;
            for(var i=0;i<canvasConfig.width*canvasConfig.height;i++){
                gray=pixelData[4*i+0]*0.3+pixelData[4*i+1]*0.59+pixelData[4*i+2]*0.11;
                pixelData[4*i+0]=gray;
                pixelData[4*i+1]=gray;
                pixelData[4*i+2]=gray;
            }
        }});
        filters.push({name:"黑白",func:function(pixelData){
            //r、g、b、a
            //黑白滤镜公式: 0 or 255
            var gray;
            for(var i=0;i<canvasConfig.width*canvasConfig.height;i++){
                gray=pixelData[4*i+0]*0.3+pixelData[4*i+1]*0.59+pixelData[4*i+2]*0.11;
                if(gray>255/2){
                    gray=255;
                }
                else{
                    gray=0;
                }
                pixelData[4*i+0]=gray;
                pixelData[4*i+1]=gray;
                pixelData[4*i+2]=gray;
            }
        }});
        filters.push({name:"反色",func:function(pixelData){
            for(var i=0;i<canvasConfig.width*canvasConfig.height;i++){
                pixelData[i*4+0]=255-pixelData[i*4+0];
                pixelData[i*4+1]=255-pixelData[i*4+1];
                pixelData[i*4+2]=255-pixelData[i*4+2];
            }
        }});
        filters.push({name:"无",func:null});
        // 添加滤镜按钮
        filters.forEach(function(filter){
            var button=$("<button>"+filter.name+"</button>");
            button.on(eventName.click,function(){
                canvasConfig.filter=filter.func;
                //重绘
                draw(context,canvasConfig.img,canvasConfig.size);
            })
            $("#filters").append(button);
        });
        //下载生成的图片(只下载第一张)
        $("#download").on(eventName.click,function(){

            //将mime-type改为image/octet-stream,强制让浏览器直接download
            var _fixType = function(type) {
                type = type.toLowerCase().replace(/jpg/i, 'jpeg');
                var r = type.match(/png|jpeg|bmp|gif/)[0];
                return 'image/' + r;
            };
            var saveFile = function(data, filename){
                var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
                save_link.href = data;
                save_link.download = filename;
                var event = document.createEvent('MouseEvents');
                event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
                save_link.dispatchEvent(event);
            };
            var imgData = $("#res1")[0].toDataURL("png");
            imgData = imgData.replace(_fixType("png"),'image/octet-stream');//base64
            saveFile(imgData,"头像created on"+new Date().getTime()+"."+"png");
        });
        //上传图片
        $("#upload").on(eventName.click,function(){
            var imgData = $("#res1")[0].toDataURL("png");
            imgData = imgData.replace(/^data:image\/(png|jpg);base64,/, "");
            if(!fileServer){
                alert("请配置文件服务器地址");
                return;
            }

            var blobBin = atob(imgData);
            var array = [];
            for(var i = 0; i < blobBin.length; i++) {
                array.push(blobBin.charCodeAt(i));
            }
            var blob=new Blob([new Uint8Array(array)], {type: 'image/png'});
            var file=new File([blob],"userlogo.png", {type: 'image/png'});
            var formdata=new FormData();
            formdata.append("userlogo",file);
             $.ajax({
                type: 'POST',
                url: fileServer,
                data: formdata,
                processData: false,
                contentType: false,
                success: function (msg) {
                    $("#uploadres").text(JSON.stringify(msg));
                }
            });
        });
        //绑定选择图片事件
        $("#fileinput").change(function(){
            var file=this.files[0],
                URL = (window.webkitURL || window.URL),
                url = URL.createObjectURL(file),
                img=new Image();
            img.src=url;
            img.onload=function(){
                canvasConfig.img=img;
                canvasConfig.size=getFixedSize(img,canvas);
                draw(context,img,canvasConfig.size);
                setPicker();
            }

        });
        //移动选择框
        //绑定鼠标在选择工具上按下的事件
        $("#picker").on(eventName.down,function(e){
            e.stopPropagation();
            var start={x:e.clientX,y:e.clientY,initX:config.x,initY:config.y};
            $("#canvasContainer").on(eventName.move,function(e){
                // 将x、y限制在框内
                config.x=Math.min(Math.max(start.initX+e.clientX-start.x,0),canvasConfig.width-config.pickerSize);
                config.y=Math.min(Math.max(start.initY+e.clientY-start.y,0),canvasConfig.height-config.pickerSize);
                setPicker();
            })
        });
        //原图移动事件
        $("#container").on(eventName.down,function(e){
            e.stopPropagation();
            var start={x:e.clientX,y:e.clientY,initX:canvasConfig.offset.x,initY:canvasConfig.offset.y};
            var size=canvasConfig.size;
            $("#canvasContainer").on(eventName.move,function(e){
                // 将x、y限制在框内
                // 坐标<0  当图片大于容器  坐标>容器-图片   否则不能移动
                canvasConfig.offset.x=Math.max(Math.min(start.initX+e.clientX-start.x,0),Math.min(canvasConfig.width-size.width*canvasConfig.zoom,0));
                canvasConfig.offset.y=Math.max(Math.min(start.initY+e.clientY-start.y,0),Math.min(canvasConfig.height-size.height*canvasConfig.zoom,0));
                //重绘蒙版
                draw(context,canvasConfig.img,canvasConfig.size);
            })
        });
        //改变选择框大小事件
        $("#resize").on(eventName.down,function(e){
            e.stopPropagation();
            var start={x:e.clientX,init:config.pickerSize};
            $("#canvasContainer").on(eventName.move,function(e){
                config.pickerSize= Math.min(Math.max(start.init+e.clientX-start.x,config.minSize),config.maxSize);
                $("#picker").css({width:config.pickerSize,height:config.pickerSize});
                draw(context,canvasConfig.img,canvasConfig.size);
            })
        });
        $(document).on(eventName.up,function(e){
            $("#canvasContainer").unbind(eventName.move);
        })
        //原图放大、缩小
        $("#bigger").on(eventName.click,
时间: 2024-10-25 21:01:06

用Canvas+Javascript FileAPI 实现一个跨平台的图片剪切、滤镜处理、上传下载工具(转)的相关文章

java-Java做一个类似FileZilla的文件上传下载工具

问题描述 Java做一个类似FileZilla的文件上传下载工具 如题,想用java做这么一个工具,现在遇到几个问题: 1.怎么像图片中那样展示一个目录下面的文件,点击..可以返回上级目录,这个怎么做? 2.图片中的窗口很像windows的文件目录窗口,是不是调用了什么api?这些难道都是自己画的? 解决方案 java swing 做啊. 解决方案二: 你需要学习javax.swing这个包下面的类. JTree和JFileChooser可能对你做这个界面有帮助 javax.swing | 最常

分享一个.NET版的多选文件上传操作示例

文件上传,无刷新上传,文件批量上传,批量无刷新上传,这些词这年头好像非常多,不管那种上传能满足实际的需求就是好的,一般上传文件时,点文件浏览框,只能选 择单个文件,如果要上传多个,浏览多次,然后点击批量上传就可以了,也很好的,也不刷新也有进度显示,完全不错的.网上也有关于上传文件的能够多选的例子,点浏 览时可以按住ctrl键或者shift键选择多个,然后上传.但是好像这样的.NET版的不多,朋友发我一个整理过的Demo,之后我又稍微整理了下,觉得还好,可以分享给大家一 下,好与不好就不说,因为没

Python实现一个简单的能够上传下载的HTTP服务器

这篇文章主要介绍了用Python实现一个简单的能够上传下载的HTTP服务器,是Python网络编程学习当中的基础,本文示例基于Windows操作系统实现,需要的朋友可以参考下 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 5

如何在linux添加一个ftp用户,让其只有上传权限,没有下载权限?

问题描述 如何在linux添加一个ftp用户,让其只有上传权限,没有下载权限? 如何在linux添加一个ftp用户,让其只有上传权限,没有下载权限? 解决方案 首先你要使用一个ftp服务器端,不同的服务器端配置不同. 一般来说上传下载权限都是单独设置的,即分别设置允许上传和禁止下载即可. 参考:http://ming228.blog.51cto.com/421298/112083/ 解决方案二: http://www.cnblogs.com/bienfantaisie/archive/2011/

安卓文件上传下载-我是安卓开发学了一点,大家可以给我讲讲如何写一个上传下载的功能

问题描述 我是安卓开发学了一点,大家可以给我讲讲如何写一个上传下载的功能 安卓我是0基础,现在我们老师命令我写一个文件上传下载,可是我只看了那么一点,大家可以给我讲讲思路,自己实际案例 解决方案 首先看看你们老师的要求是上传下载到哪里?然后再搜索方法案例,因为数据存储有多种方式都不一样的 解决方案二: http://download.csdn.net/detail/airlke/8172213

应用-一个web管理端接收大量客户端上传文件的问题

问题描述 一个web管理端接收大量客户端上传文件的问题 应用场景:一个Java实现的web管理端,对应多个客户端(C++实现,客户端大约有2万台),在管理端通过设置关键字抓取客户端的命中文件,如在管理端设定"你好"关键字下发到各客户端,各客户端会自动搜索本机器上带"你好"关键字的各种类型的文件并将命中文件上报到管理,现在想问的是在管理端如何接收个客户端上传的文件,通过HTTP方式接收还是FTP方式接收,由于客户端数目较多,且可能由于关键字设置过于普通(如"

jsp 中一个file 怎么实现多个文件上传

问题描述 jsp 中一个file 怎么实现多个文件上传 jsp 中一个file 怎么实现多个文件上传.图片还能在本页显示.当点击提交时.图片才保存到数据库中.

文件上传 apk-求一个可以自动解析APK文件的上传控件

问题描述 求一个可以自动解析APK文件的上传控件 在做一个Java项目,要上传APK文件,哪位大神知道那种可以自动解析APK文件的上传控件啊?

我用anthem.net组件实现上传下载功能,绑定gridview提交成功后怎么弹出一个对话框提示成功啊?在线等高手!

问题描述 我用anthem.net组件实现上传下载功能,提交成功后怎么弹出一个对话框提示成功啊?我的怎么不提示成功直接就在线下面出来了,我用response.write(<script>alert('提交成功')</script>);弹不出来提示成功的对话窗口啊!在线等啊! 解决方案 解决方案二:Anthem不能用response.write要用Anthem.Manager.AddScriptForClientSideEval("alert('提交成功')");