全国服务热线:4008-888-888

技术知识

根据Canvas及File API放缩并提交照片详细示例

示例详细地址:Canvas Resize Demo
原文作者:Dr. Tom Trenka
原文时间: 2013年8月6日
汉语翻译时间: 2013年8月8日

Tom Trenka 能为"我"的blog写1篇文章内容,对我来讲是1个极大的殊荣。Tom是Dojo架构的最开始奉献者之1,也是我在SitePen企业的良师良友.我见证了他最顶级的奇才工作能力,而且他一直第1个之前瞻性的处理计划方案预料了许多繁杂的难题。他一直站在局外思索,摆脱基本但却又坚实靠谱地处理边沿难题。本文便是1个完善的例子。
近期我一直被问道要造就1个客户插口API,容许客户提交照片到服务器上(随着别的的事儿),并能在大家企业出示适用的很多网站的顾客端上应用。一般来讲这全是很非常容易的事儿——建立1个form表单,加上1个file种类的input键入框,让客户从电脑上里挑选照片,并在form标识上设定enctype="multipart/form-data"表单特性,随后提交便可。十分简易,并不是吗?客观事实上,这里有1个充足简易的事例;点一下进到
可是假如你要想根据一些方法预先解决1下照片再提交,那应该怎么办?例如说,你务必先缩小照片规格,或必须照片只能是一些类型的文件格式,如 png 或jpg,你如何办?
用canvas来处理!

Canvas简介
canvas 是1个HTML5新增的DOM元素,容许客户在网页页面上立即地绘图图型,一般是应用JavaScript.而不一样的文件格式规范也是不一样的,例如SVG是光纤传感器API(raster API) 而VML确是空间向量API(vector API).能够考虑到应用Adobe Illustrator(矢量图)作图与应用 Adobe Photoshop (光纤传感器图)作图的差别。

在canvas(画布)上能做的事儿便是载入和3D渲染图象,而且容许你根据JavaScript控制图象数据信息。早已有许多现存的文章内容来为你演试基础的图象解决——关键关心与各种各样不一样的图象过虑技术性( image filtering techniques)——但大家必须的仅仅是放缩照片并变换到特殊的文档文件格式,而canvas彻底能够保证这些事儿。

大家假设的要求,例如图象高宽比不超出100像素,无论初始图象有多高。基础的编码以下所示:

拷贝编码
编码以下:

// 主要参数,最大高宽比
var MAX_HEIGHT = 100;
// 3D渲染
function render(src){
// 建立1个 Image 目标
var image = new Image();
// 关联 load 恶性事件解决器,载入进行后实行
image.onload = function(){
// 获得 canvas DOM 目标
var canvas = document.getElementById("myCanvas");
// 假如高宽比超标准
if(image.height > MAX_HEIGHT) {
// 宽度等占比放缩 *=
image.width *= MAX_HEIGHT / image.height;
image.height = MAX_HEIGHT;
}
// 获得 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;
};

在上面的事例中,你可使用canvas 的 toDataURL() 方式获得图象的 Base64编号的值(能够相近了解为16进制标识符串,或2进制数据信息流).
留意: canvas 的 toDataURL() 获得的URL以标识符串开始,有22个无用的数据信息 "data:image/png;base64,",必须在顾客端或服务端开展过虑.
标准上要是访问器适用,URL详细地址的长度是沒有限定的,而1024的长度限定,是老1代IE所特有的。

请问,怎样获得大家必须的图象呢?
好孩子,很开心你能这么问。你其实不能根据File 键入框来立即解决,你从这个文档键入框元素所能获得的仅仅是客户所挑选文档的path相对路径。依照基本想像,你能够根据这个path相对路径信息内容来载入图象,可是,在访问器里边这是不实际的。(译者注:访问器厂商务必确保自身的访问器肯定安全性,才可以得到销售市场,最少防止新闻媒体的进攻,假如容许这样做,那故意网站地址能够根据拼凑文档相对路径来尝试获得一些比较敏感信息内容).
以便完成这个要求,大家可使用HTML5的File API 来载入客户硬盘上的文档,并用这个file来做为图象的源(src,source).

File API简介
新的File API插口是在不违反任何安全性沙盒游戏标准下,载入和列出客户文档文件目录的1个方式—— 根据沙盒游戏(sandbox)限定,故意网站其实不能将病毒感染写入客户硬盘,自然更不可以实行。
大家要应用的文档载入目标叫做 FileReader,FileReader容许开发设计者载入文档的內容(实际访问器的完成方法将会大不一样)。

假定大家早已获得了图象文档的path相对路径,那末依靠前面的编码,应用FileReader来载入和3D渲染图象就变得很非常容易了:

拷贝编码
编码以下:

// 载入 图象文档(url相对路径)
function loadImage(src){
// 过虑掉 非 image 种类的文档
if(!src.type.match(/image.*/)){
if(window.console){
console.log("挑选的文档种类并不是照片: ", src.type);
} else {
window.confirm("只能挑选照片文档");
}
return;
}
// 建立 FileReader 目标 并启用 render 涵数来进行3D渲染.
var reader = new FileReader();
// 关联load恶性事件全自动回调函数涵数
reader.onload = function(e){
// 启用前面的 render 涵数
render(e.target.result);
};
// 载入文档內容
reader.readAsDataURL(src);
};

请问,怎样获得文档呢?
小白兔,要有细心!大家的下1步便是获得文档,自然有许多方式能够完成啦。比如:你能够用文字框让客户键入文档相对路径,但很明显大多数数客户都并不是开发设计者,对键入甚么值压根就不上解.
以便客户应用便捷,大家选用 Drag and Drop API插口。

应用 Drag and Drop API
拖拽插口(Drag and Drop)十分简易——在大多数数的DOM元素上,你都可以以根据关联恶性事件解决器来完成. 要是客户从硬盘上拖拽1个文档到dom目标上并放宽电脑鼠标,那大家便可以载入这个文档。编码以下:

拷贝编码
编码以下:

function init(){
// 获得DOM元素目标
var target = document.getElementById("drop-target");
// 阻拦 dragover(拖到DOM元素上方) 恶性事件传送
target.addEventListener("dragover", function(e){e.preventDefault();}, true);
// 拖拽并放宽电脑鼠标的恶性事件
target.addEventListener("drop", function(e){
// 阻拦默认设置恶性事件,和恶性事件散播
e.preventDefault();
// 启用前面的载入图象 涵数,主要参数为dataTransfer目标的第1个文档
loadImage(e.dataTransfer.files[0]);
}, true);
var setheight = document.getElementById("setheight");
var maxheight = document.getElementById("maxheight");
setheight.addEventListener("click", function(e){
//
var value = maxheight.value;
if(/^\d+$/.test(value)){
MAX_HEIGHT = parseInt(value);
}
e.preventDefault();
},true);
var btnsend = document.getElementById("btnsend");
btnsend.addEventListener("click", function(e){
//
sendImage();
},true);
};

大家还能够做1些别的的解决,例如显示信息预览图。但假如不想缩小照片的话,那极可能没甚么用。大家将选用Ajax根据HTTP 的post方法提交照片数据信息。下面的事例是应用Dojo架构来进行恳求的,自然你还可以选用别的的Ajax技术性来完成.
Dojo 编码以下:

拷贝编码
编码以下:

// 译者其实不懂Dojo,因此将在后边附上jQuery的完成
// Remember that DTK 1.7+ is AMD!
require(["dojo/request"], function(request){
// 设定恳求URL,主要参数,和回调函数。
request.post("image-handler.php", {
data: {
imageName: "myImage.png",
imageData: encodeURIComponent(document.getElementById("canvas").toDataURL("image/png"))
}
}).then(function(text){
console.log("The server returned: ", text);
});
});

jQuery 完成以下:

拷贝编码
编码以下:

// 提交照片,jQuery版
function sendImage(){
// 获得 canvas DOM 目标
var canvas = document.getElementById("myCanvas");
// 获得Base64编号后的图象数据信息,文件格式是标识符串
// "data:image/png;base64,"开始,必须在顾客端或服务器端将其去掉,后边的一部分能够立即写入文档。
var dataurl = canvas.toDataURL("image/png");
// 为安全性 对URI开展编号
// data%3Aimage%2Fpng%3Bbase64%2C 开始
var imagedata = encodeURIComponent(dataurl);
//var url = $("#form").attr("action");
// 1. 假如form表单不太好解决,可使用某个hidden掩藏域来设定恳求详细地址
// <input type="hidden" name="action" value="receive.jsp" />
var url = $("input[name='action']").val();
// 2. 还可以立即用某个dom目标的特性来获得
// <input id="imageaction" type="hidden" action="receive.jsp">
// var url = $("#imageaction").attr("action");
// 由于是string,因此服务器必须对数据信息开展转码,写文档实际操作等。
// 本人承诺,全部http主要参数姓名所有小写
console.log(dataurl);
//console.log(imagedata);
var data = {
imagename: "myImage.png",
imagedata: imagedata
};
jQuery.ajax( {
url : url,
data : data,
type : "POST",
// 希望的回到值种类
dataType: "json",
complete : function(xhr,result) {
//console.log(xhr.responseText);
var $tip2 = $("#tip2");
if(!xhr){
$tip2.text('互联网联接不成功!');
return false;
}
var text = xhr.responseText;
if(!text){
$tip2.text('互联网不正确!');
return false;
}
var json = eval("("+text+")");
if(!json){
$tip2.text('分析不正确!');
return false;
} else {
$tip2.text(json.message);
}
//console.dir(json);
//console.log(xhr.responseText);
}
});
};

OK,搞定!你还必须做的,便是建立1个只要的客户页面,并容许你操纵照片的尺寸。提交到服务器端数据信息,其实不必须解决enctype为 multi-part/form-data 的状况,仅仅1个简易的POST表单解决程序流程便可以了.
好了,下面附上详细的编码示例:

拷贝编码
编码以下:

<%@ page language="java" import="java.util.*" pageEncoding="UTF⑻"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html>
<html>
<head>
<title>根据Canvas及File API放缩并提交照片</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="Canvas,File,Image">
<meta http-equiv="description" content="2013年8月8日,renfufei">
<script src="http://code.jquery.com/jquery⑴.7.1.min.js"></script>
<script>
// 主要参数,最大高宽比
var MAX_HEIGHT = 100;
// 3D渲染
function render(src){
// 建立1个 Image 目标
var image = new Image();
// 关联 load 恶性事件解决器,载入进行后实行
image.onload = function(){
// 获得 canvas DOM 目标
var canvas = document.getElementById("myCanvas");
// 假如高宽比超标准
if(image.height > MAX_HEIGHT) {
// 宽度等占比放缩 *=
image.width *= MAX_HEIGHT / image.height;
image.height = MAX_HEIGHT;
}
// 获得 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;
};
// 载入 图象文档(url相对路径)
function loadImage(src){
// 过虑掉 非 image 种类的文档
if(!src.type.match(/image.*/)){
if(window.console){
console.log("挑选的文档种类并不是照片: ", src.type);
} else {
window.confirm("只能挑选照片文档");
}
return;
}
// 建立 FileReader 目标 并启用 render 涵数来进行3D渲染.
var reader = new FileReader();
// 关联load恶性事件全自动回调函数涵数
reader.onload = function(e){
// 启用前面的 render 涵数
render(e.target.result);
};
// 载入文档內容
reader.readAsDataURL(src);
};
// 提交照片,jQuery版
function sendImage(){
// 获得 canvas DOM 目标
var canvas = document.getElementById("myCanvas");
// 获得Base64编号后的图象数据信息,文件格式是标识符串
// "data:image/png;base64,"开始,必须在顾客端或服务器端将其去掉,后边的一部分能够立即写入文档。
var dataurl = canvas.toDataURL("image/png");
// 为安全性 对URI开展编号
// data%3Aimage%2Fpng%3Bbase64%2C 开始
var imagedata = encodeURIComponent(dataurl);
//var url = $("#form").attr("action");
// 1. 假如form表单不太好解决,可使用某个hidden掩藏域来设定恳求详细地址
// <input type="hidden" name="action" value="receive.jsp" />
var url = $("input[name='action']").val();
// 2. 还可以立即用某个dom目标的特性来获得
// <input id="imageaction" type="hidden" action="receive.jsp">
// var url = $("#imageaction").attr("action");
// 由于是string,因此服务器必须对数据信息开展转码,写文档实际操作等。
// 本人承诺,全部http主要参数姓名所有小写
console.log(dataurl);
//console.log(imagedata);
var data = {
imagename: "myImage.png",
imagedata: imagedata
};
jQuery.ajax( {
url : url,
data : data,
type : "POST",
// 希望的回到值种类
dataType: "json",
complete : function(xhr,result) {
//console.log(xhr.responseText);
var $tip2 = $("#tip2");
if(!xhr){
$tip2.text('互联网联接不成功!');
return false;
}
var text = xhr.responseText;
if(!text){
$tip2.text('互联网不正确!');
return false;
}
var json = eval("("+text+")");
if(!json){
$tip2.text('分析不正确!');
return false;
} else {
$tip2.text(json.message);
}
//console.dir(json);
//console.log(xhr.responseText);
}
});
};
function init(){
// 获得DOM元素目标
var target = document.getElementById("drop-target");
// 阻拦 dragover(拖到DOM元素上方) 恶性事件传送
target.addEventListener("dragover", function(e){e.preventDefault();}, true);
// 拖拽并放宽电脑鼠标的恶性事件
target.addEventListener("drop", function(e){
// 阻拦默认设置恶性事件,和恶性事件散播
e.preventDefault();
// 启用前面的载入图象 涵数,主要参数为dataTransfer目标的第1个文档
loadImage(e.dataTransfer.files[0]);
}, true);
var setheight = document.getElementById("setheight");
var maxheight = document.getElementById("maxheight");
setheight.addEventListener("click", function(e){
//
var value = maxheight.value;
if(/^\d+$/.test(value)){
MAX_HEIGHT = parseInt(value);
}
e.preventDefault();
},true);
var btnsend = document.getElementById("btnsend");
btnsend.addEventListener("click", function(e){
//
sendImage();
},true);
};
window.addEventListener("DOMContentLoaded", function() {
//
init();
},false);
</script>
</head>
<body>
<div>
<h1>根据Canvas及File API放缩并提交照片</h1>
<p>从文档夹拖拽1张相片到正下方的盒子里, canvas 和 JavaScript可能全自动的开展放缩.</p>
<div>
<input type="text" id="maxheight" value="100"/>
<button id="setheight">设定照片最大高宽比</button>
<input type="hidden" name="action" value="receive.jsp" />
</div>
<div id="preview-row">
<div id="drop-target" style="width:400px;height:200px;min-height:100px;min-width:200px;background:#eee;cursor:pointer;">拖拽照片文档到这里...</div>
<div>
<div>
<button id="btnsend"> 上 传 </button> <span id="tip2" style="padding:8px 0;color:#f00;"></span>
</div>
</div>
<div><h4>缩略图:</h4></div>
<div id="preview" style="background:#f4f4f4;width:400px;height:200px;min-height:100px;min-width:200px;">
<canvas id="myCanvas"></canvas>
</div>
</div>
</div>
</body>
</html>

服务端网页页面,receive.jsp

拷贝编码
编码以下:

<%@ page language="java" import="java.util.*" pageEncoding="UTF⑻"%>
<%@page import="sun.misc.BASE64Decoder"%>
<%@page import="java.io.*"%>
<%@page import="org.springframework.web.util.UriComponents"%>
<%@page import="java.net.URLDecoder"%>
<%!
// 本文档:/receive.jsp
// 照片储放相对路径
String photoPath = "D:/blog/upload/photo/";
File photoPathFile = new File(photoPath);
// references: http://blog.csdn.net/remote_roamer/article/details/2979822
private boolean saveImageToDisk(byte[] data,String imageName) throws IOException{
int len = data.length;
//
// 写入到文档
FileOutputStream outputStream = new FileOutputStream(new File(photoPathFile,imageName));
outputStream.write(data);
outputStream.flush();
outputStream.close();
//
return true;
}
private byte[] decode(String imageData) throws IOException{
BASE64Decoder decoder = new BASE64Decoder();
byte[] data = decoder.decodeBuffer(imageData);
for(int i=0;i<data.length;++i)
{
if(data[i]<0)
{
//调剂出现异常数据信息
data[i]+=256;
}
}
//
return data;
}
%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%
//假如是IE,那末必须设定为text/html,不然会弹框免费下载
//response.setContentType("text/html;charset=UTF⑻");
response.setContentType("application/json;charset=UTF⑻");
//
String imageName = request.getParameter("imagename");
String imageData = request.getParameter("imagedata");
int success = 0;
String message = "";
if(null == imageData || imageData.length() < 100){
// 数据信息过短,显著不符合理
message = "提交不成功,数据信息过短或不存在";
} else {
// 除去开始不符合理的数据信息
imageData = imageData.substring(30);
imageData = URLDecoder.decode(imageData,"UTF⑻");
//System.out.println(imageData);
byte[] data = decode(imageData);
int len = data.length;
int len2 = imageData.length();
if(null == imageName || imageName.length() < 1){
imageName = System.currentTimeMillis()+".png";
}
saveImageToDisk(data,imageName);
//
success = 1;
message = "提交取得成功,主要参数长度:"+len2+"标识符,分析文档尺寸:"+len+"字节";
}
// 后台管理复印
System.out.println("message="+message);
%>
{
"message": "<%=message %>",
"success": <%=success %>
}


在线客服

关闭

客户服务热线
4008-888-888


点击这里给我发消息 在线客服

点击这里给我发消息 在线客服