This article mainly introduces how to zoom and upload pictures through Canvas and File API. It has certain reference value. Now I share it with you. Friends in need can refer to it.
Create a user who only cares interface and allows you to control the size of the image. The data uploaded to the server does not need to handle the enctype of multi-part/form-data. Just a simple POST form handler is enough. Well, the complete code example is attached below
Example address: Canvas Resize Demo
Original author: Dr. Tom Trenka
Original date: August 6, 2013
Translation date: August 8, 2013
Tom Trenka can help Writing an article for "my" blog is a huge honor for me. Tom was one of the original contributors to the Dojo framework and was my mentor at SitePen. I witnessed his genius at the highest level, and he was always the first to foresee many difficult problems with forward-looking solutions. He always thinks from the outside and solves fringe problems in an unconventional but solid way. This article is a perfect example.
Lately I've been asked a lot about creating a user interface API that would allow users to upload images to a server (among other things) and be used on the client side of the large number of websites our company supports. Usually this is a very easy thing - create a form, add a file type input box, let the user select an image from the computer, and set the enctype="multipart/form-data" form on the form tag properties and then upload. Pretty simple, isn't it? In fact, here's a simple enough example; click to enter
But what if you want to pre-process the image in some way before uploading it? For example, you must compress the image size first, or you need the image to be in only certain types of formats, such as png or jpg, what should you do?
Use canvas to solve it!
Introduction to Canvas
Canvas is a new DOM element in HTML5 that allows users to draw graphics directly on the page, usually using JavaScript. Different format standards are also different. For example, SVG is a raster API (raster API) while VML is a vector API. You can consider using Adobe Illustrator (vector) for drawing and Adobe Photoshop (raster) for drawing. difference.
What you can do on canvas (canvas) is to read and render images, and allow you to manipulate image data through JavaScript. There are many existing articles that demonstrate basic image processing for you - focusing mainly on various image filtering techniques - but all we need is to scale the image and convert it to a specific file format, and Canvas can do these things completely.
Our assumed requirements, such as the image height not exceeding 100 pixels, no matter how high the original image is. The basic code is as follows:
// 参数,最大高度 var MAX_HEIGHT = 100; // 渲染 function render(src){ // 创建一个 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; };
In the above example, you can use the toDataURL() method of canvas to obtain the Base64 encoded value of the image (which can be similarly understood as a hexadecimal string, or binary data stream).
Note: The URL obtained by canvas's toDataURL() starts with a string and has 22 useless data "data:image/png;base64," which needs to be filtered on the client or server.
In principle, as long as the browser supports it, there is no limit to the length of the URL address, and the length limit of 1024 is unique to the older generation of IE.
Excuse me, how to get the images we need?
Good boy, I’m glad you asked. You cannot process it directly through the File input box. All you can get from this file input box element is only the path to the file selected by the user. According to conventional imagination, you can load images through this path path information, but this is unrealistic in the browser. (Translator's note: Browser manufacturers must ensure that their browsers are absolutely secure in order to gain market share, at least to avoid media attacks. If this is allowed, malicious URLs can try to obtain certain sensitive information by piecing together file paths).
In order to achieve this requirement, we can use the File API of HTML5 to read the file on the user's disk and use this file as the source of the image (src, source).
File API Introduction
The new File API interface is a way to read and list user file directories without violating any security sandbox rules - through sandbox restrictions, malicious websites cannot write viruses User disks, of course, cannot be executed.
The file reading object we want to use is called FileReader. FileReader allows developers to read the contents of files (the implementation of specific browsers may be very different).
Assuming that we have obtained the path path of the image file, then relying on the previous code, it becomes very easy to use FileReader to load and render the image:
// 加载 图像文件(url路径) function loadImage(src){ // 过滤掉 非 image 类型的文件 if(!src.type.match(/image.*/)){ if(window.console){ console.log("选择的文件类型不是图片: ", src.type); } else { window.confirm("只能选择图片文件"); } return; } // 创建 FileReader 对象 并调用 render 函数来完成渲染. var reader = new FileReader(); // 绑定load事件自动回调函数 reader.onload = function(e){ // 调用前面的 render 函数 render(e.target.result); }; // 读取文件内容 reader.readAsDataURL(src); };
请问,如何获取文件呢?
小白兔,要有耐心!我们的下一步就是获取文件,当然有好多方法可以实现啦。例如:你可以用文本框让用户输入文件路径,但很显然大多数用户都不是开发者,对输入什么值根本就不了解.
为了用户使用方便,我们采用 Drag and Drop API接口。
使用 Drag and Drop API
拖拽接口(Drag and Drop)非常简单——在大多数的DOM元素上,你都可以通过绑定事件处理器来实现. 只要用户从磁盘上拖动一个文件到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对象的第一个文件 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); };
我们还可以做一些其他的处理,比如显示预览图。但如果不想压缩图片的话,那很可能没什么用。我们将采用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,搞定!你还需要做的,就是创建一个只管的用户界面,并允许你控制图片的大小。上传到服务器端的数据,并不需要处理enctype为 multi-part/form-data 的情况,仅仅一个简单的POST表单处理程序就可以了.
好了,下面附上完整的代码示例:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %>通过Canvas及File API缩放并上传图片 <script> // 参数,最大高度 var MAX_HEIGHT = 100; // 渲染 function render(src){ // 创建一个 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 函数来完成渲染. 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对象的第一个文件 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>
通过Canvas及File API缩放并上传图片
从文件夹拖动一张照片到下方的盒子里, canvas 和 JavaScript将会自动的进行缩放.
拖动图片文件到这里...
缩略图:
服务端页面,receive.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@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-8"); response.setContentType("application/json;charset=UTF-8"); // 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-8"); //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 %> }
以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!
相关推荐:
借助toDataURL实现将HTML5 Canvas的内容保存为图片
The above is the detailed content of How to zoom and upload images through Canvas and File API. For more information, please follow other related articles on the PHP Chinese website!