HTML5 带有一组非常棒的 API。如果你将这些 API 与 <canvas> 元素结合起来,就可以创建一个超级/现代/棒的图片上传器。本文将向你展示如何做到这一点。
所有这些技巧在 Firefox 4 中都能很好地工作。我还会描述一些替代方法来确保它在基于 Webkit 的浏览器中也能正常工作。大多数 API 在 IE 中无法正常工作,但使用普通表单作为后备非常容易。
如果你在项目中使用这些技术中的任何一项,请告诉我们!
检索图片
拖放
要上传文件,你需要一个 <input type=”file”> 元素。但你还可以允许用户将图片从桌面直接拖放到网页上。
我已经写了一篇关于 为你的网页实现拖放支持 的详细文章。
此外,还可以查看 Mozilla 关于拖放的教程。
多重输入
允许用户从文件选择器中同时选择多个文件上传。
同样,这里有一篇我写的关于 多重文件选择 的文章。
预处理文件
使用 File API
(有关详细信息,请参阅 File API 文档。)
从拖放或从 <input> 元素中,你将获得一个准备使用的文件列表。
// from an input element
var filesToUpload = input.files;
// from drag-and-drop
function onDrop(e) {
filesToUpload = e.dataTransfer.files;
}
确保这些文件实际上是图片
if (!file.type.match(/image.*/)) {
// this file is not an image.
};
显示缩略图/预览
这里有两个选项。你可以使用 FileReader (来自 File API) 或使用新的 createObjectURL()
方法。
createObjectURL()
var img = document.createElement("img");
img.src = window.URL.createObjectURL(file);
FileReader
var img = document.createElement("img");
var reader = new FileReader();
reader.onload = function(e) {img.src = e.target.result}
reader.readAsDataURL(file);
使用画布
一旦你在一个 <img> 元素中拥有图片预览,你就可以将此图片绘制在一个 <canvas> 元素中来预处理文件。
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
调整图片大小
人们习惯于直接从他们的相机上传图片。这会生成高分辨率和极重的 (几兆字节) 文件。根据用途,你可能需要调整这些图片的大小。一个超级简单的技巧是简单地使用一个小的画布 (例如 800×600),然后将图片标签绘制到此画布中。当然,你需要更新画布的尺寸以保持图片的比例。
var MAX_WIDTH = 800;
var MAX_HEIGHT = 600;
var width = img.width;
var height = img.height;
if (width > height) {
if (width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
}
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);
编辑图片
现在,你在画布中拥有你的图片。基本上,可能性是无限的。假设你想应用一个棕褐色滤镜。
var imgData = ctx.createImageData(width, height);
var data = imgData.data;
var pixels = ctx.getImageData(0, 0, width, height);
for (var i = 0, ii = pixels.data.length; i < ii; i += 4) {
var r = pixels.data[i + 0];
var g =pixels.data[i + 1];
var b = this.pixels.data[i + 2];
data[i + 0] = (r * .393) + (g *.769) + (b * .189);
data[i + 1] = (r * .349) + (g *.686) + (b * .168)
data[i + 2] = (r * .272) + (g *.534) + (b * .131)
data[i + 3] = 255;
}
ctx.putImageData(imgData, 0, 0);
使用 XMLHttpRequest 上传
现在你在客户端已经加载了图片,最终你想将它们发送到服务器。
如何发送画布
同样,你有两个选项。你可以 将画布转换为数据 URL 或 (在 Firefox 中) 从画布中创建一个文件。
canvas.toDataURL()
var dataurl = canvas.toDataURL("image/png");
从画布中创建一个文件
var file = canvas.mozGetAsFile("foo.png");
原子上传
允许用户同时上传一个文件或所有文件。
显示上传进度
使用上传事件创建一个进度条
xhr.upload.addEventListener("progress", function(e) {
if (e.lengthComputable) {
var percentage = Math.round((e.loaded * 100) / e.total);
// do something
}, false);
使用 FormData
你可能不想只是上传文件 (这可以通过 xhr.send(file)
很容易完成),而是添加一些辅助信息 (如密钥和名称)。
在这种情况下,你需要通过一个 FormData
对象创建一个 multipart/form-data
请求。(请参阅 Firefox 4: 使用 FormData 简化 JS 表单处理。)
var fd = new FormData();
fd.append("name", "paul");
fd.append("image", canvas.mozGetAsFile("foo.png"));
fd.append("key", "××××××××××××");
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://your.api.com/upload.json");
xhr.send(fd);
打开你的 API
也许你想允许其他网站使用你的服务。
允许跨域请求
默认情况下,你的 API 只能从你的域创建的请求访问。如果你想允许人们使用你的 API,请在你的 HTTP 头中允许 Cross-XHR。
Access-Control-Allow-Origin: *
你还可以只允许一个预定义的域列表。
阅读关于 跨域资源共享 的内容。
postMessage
(感谢 Daniel Goodwin 提供的这个提示。)
此外,请监听从 postMessage
发送的消息。你可以允许人们通过 postMessage 使用你的 API。
document.addEventListener("message", function(e){
// retrieve parameters from e.data
var key = e.data.key;
var name = e.data.name;
var dataurl = e.data.dataurl;
// Upload
}
// Once the upload is done, you can send a postMessage to the original window, with URL
以上就是所有内容。如果你有任何其他技巧要分享,请随时发表评论。
享受;)
关于 Paul Rouget
Paul 是 Firefox 开发者。
40 条评论