Complete example of scaling and uploading images through Canvas and File APIs

Source: Internet
Author: User

Comments: Create a simple user interface and allow you to control the image size. The data uploaded to the server does not need to be processed if the enctype is multi-part/form-data. It is just a simple POST form processing program. the following is a complete sample code: Canvas Resize Demo.
Author: Dr. Tom Trenka
Original Article Date: January 1, August 6, 2013
Translated on: February 1, August 8, 2013

It is a great honor for me to write an article for my blog by Tom Trenka. Tom was one of the first contributors to the Dojo framework and a mentor to me at SitePen. I have witnessed his top talents, and he is always the first to anticipate many tough problems with a proactive solution. He always thinks outside of the board, breaking the regular but solid and reliable to solve the edge problem. This article is a perfect example.
Recently, I have been asked to create a user interface API that allows users to upload images to the server (with other things ), it can also be used on clients of a large number of websites supported by our company. This is usually easy-create a form and add a file-type input box for users to select images from their computers, set the enctype = "multipart/form-data" form attribute on the form tag, and then upload it. It's very simple, isn't it? In fact, there is a simple example here; click to enter
But what if you want to pre-process one part and then upload it in some ways? For example, you must first compress the image size, or the image must be in some formats, such as png or jpg. What should you do?
Use canvas!

Canvas Introduction
Canvas is a newly added DOM element in HTML5. It allows users to draw images directly on pages, usually using JavaScript. different format standards are also different. For example, SVG is a raster API, while VML is a vector API ). consider the difference between drawing with Adobe Illustrator (vector graph) and using Adobe Photoshop (grating graph.

What can be done on the canvas is to read and render the image and allow you to manipulate the image data through JavaScript. There are already many existing articles to demonstrate basic image Processing for you-mainly focusing on different image filtering technologies (image filtering techniques) -- but all we need is to scale the image and convert it to a specific file format, which canvas can do.

We assume that the requirement is no more than 100 pixels higher than the Image Height, no matter how high the original image is. The basic code is as follows:

The Code is as follows:
// Parameter, maximum height
Var MAX_HEIGHT = 100;
// Rendering
Function render (src ){
// Create an Image object
Var image = new Image ();
// Bind the load event processor and run it after loading.
Image. onload = function (){
// Obtain the canvas DOM object
Var canvas = document. getElementById ("myCanvas ");
// If the height exceeds the standard
If (image. height> MAX_HEIGHT ){
// Proportional scaling like width * =
Image. width * = MAX_HEIGHT/image. height;
Image. height = MAX_HEIGHT;
}
// Obtain the 2d environment object of the canvas,
// You can understand that Context is the administrator and canvas is the house.
Var ctx = canvas. getContext ("2d ");
// Canvas clear screen
Ctx. clearRect (0, 0, canvas. width, canvas. height );
// Reset the canvas width and height
Canvas. width = image. width;
Canvas. height = image. height;
// Draw the image to the canvas
Ctx. drawImage (image, 0, 0, image. width, image. height );
//!!! Note: The image is not added to the dom.
};
// Set the src attribute, which is automatically loaded by the browser.
// Remember that you must bind an event before setting the src attribute. Otherwise, synchronization may fail.
Image. src = src;
};

In the preceding example, you can use the toDataURL () method of canvas to obtain the Base64 encoded value of the image (which can be understood as a hexadecimal string or binary data stream ).
Note: The URL obtained by the toDataURL () of canvas starts with a string and has 22 useless data "data: image/png; base64,", which must be filtered on the client or server.
In principle, as long as the browser supports it, there is no limit on the length of the URL address, and the length of 1024 is exclusive to the older generation of IE.

How can we get the images we need?
Good boy, I'm glad you asked this question. You cannot directly process the File in the File input box. All you can obtain from the File input box is the path of the File selected by the user. As you can imagine, you can use the path information to load images. However, this is unrealistic in the browser. (Translator's note: browser vendors must ensure that their browsers are absolutely secure in order to obtain the market, at least to avoid media attacks. If this is permitted, the malicious website can try to obtain some sensitive information by splicing the file path ).
To meet this requirement, we can use the HTML5 File API to read files on the user's disk and use this file as the image source (src, source ).

File API Introduction
The new File API is a way to read and list user File directories without violating any Security sandbox rules-through sandbox restrictions, malicious websites cannot write viruses to users' disks.
The object to be read from is called FileReader. FileReader allows developers to read the content of the file (The implementation methods of specific browsers may vary greatly ).

Assuming that we have obtained the path of the image file, it is easy to use FileReader to load and render the image based on the previous Code:

The Code is as follows:
// Load the image file (url path)
Function loadImage (src ){
// Filter out non-image files
If (! Src. type. match (/image .*/)){
If (window. console ){
Console. log ("the selected file type is not an image:", src. type );
} Else {
Window. confirm ("only image files can be selected ");
}
Return;
}
// Create a FileReader object and call the render function to complete rendering.
Var reader = new FileReader ();
// Bind the load event automatic callback function
Reader. onload = function (e ){
// Call the preceding render Function
Render(e.tar get. result );
};
// Read the file content
Reader. readAsDataURL (src );
};

How can I obtain files?
Patience! Our next step is to get the file. Of course there are many ways to implement it. For example, you can use text boxes to allow users to enter the file path. However, it is clear that most users are not developers and do not know the input value.
We use the Drag and Drop API for ease of use.

Use Drag and Drop API
The Drag and Drop interface is very simple-you can bind event handlers to most DOM elements. you can read this file as long as you drag a file from the disk to the dom object and open the mouse. The Code is as follows:

The Code is as follows:
Function init (){
// Obtain the DOM Element Object
Var target = document. getElementById ("drop-target ");
// Stop dragover (drag to the top of the DOM element) event Transmission
Target. addEventListener ("dragover", function (e) {e. preventDefault () ;}, true );
// Drag and release the mouse event
Target. addEventListener ("drop", function (e ){
// Block default events and event Propagation
E. preventDefault ();
// Call the previous image loading function. The parameter is the first file of the dataTransfer object.
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 );
};

We can also do some other processing, such as displaying a preview image. However, if you do not want to compress the image, it may be useless. We will use Ajax to upload image data through HTTP post. The following example uses the Dojo framework to complete the request. Of course, you can also use other Ajax technologies.
The Dojo code is as follows:

The Code is as follows:
// The Translator does not understand Dojo, so the jQuery implementation will be attached later.
// Remember that DTK 1.7 + is AMD!
Require (["dojo/request"], function (request ){
// Set the request URL, parameters, and callback.
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 implementation is as follows:

The Code is as follows:
// Upload the image, jQuery version
Function sendImage (){
// Obtain the canvas DOM object
Var canvas = document. getElementById ("myCanvas ");
// Obtain Base64 encoded image data in the format of a string
// "Data: image/png; base64," must be removed from the client or server, and the subsequent parts can be directly written into the file.
Var dataurl = canvas. toDataURL ("image/png ");
// Encode the URI for security purposes
// Data % 3 Aimage % 2 Fpng % 3Bbase64% 2C start
Var imagedata = encodeURIComponent (dataurl );
// Var url = $ ("# form"). attr ("action ");
// 1. If the form is not easy to process, you can use a hidden field to set the request address.
// <Input type = "hidden" name = "action" value = "receive. jsp"/>
Var url = $ ("input [name = 'action']"). val ();
// 2. You can also directly obtain the attributes of a dom object.
// <Input id = "imageaction" type = "hidden" action = "receive. jsp">
// Var url = $ ("# imageaction"). attr ("action ");
// Because it is a string, the server needs to transcode the data and write files.
// Individual conventions, all http parameter names are in lowercase
Console. log (dataurl );
// Console. log (imagedata );
Var data = {
Imagename: "myImage.png ",
Imagedata: imagedata
};
JQuery. ajax ({
Url: url,
Data: data,
Type: "POST ",
// Expected Return Value Type
DataType: "json ",
Complete: function (xhr, result ){
// Console. log (xhr. responseText );
Var $ tip2 = $ ("# tip2 ");
If (! Xhr ){
$ Tip2.text ('network connection failed! ');
Return false;
}
Var text = xhr. responseText;
If (! Text ){
$ Tip2.text ('network error! ');
Return false;
}
Var json = eval ("(" + text + ")");
If (! Json ){
$ Tip2.text ('parsing error! ');
Return false;
} Else {
$ Tip2.text (json. message );
}
// Console. dir (json );
// Console. log (xhr. responseText );
}
});
};

OK! What you need to do is to create a just user interface and allow you to control the image size. The data uploaded to the server does not need to be processed if the enctype is multi-part/form-data. It is just a simple POST form processing program.
A complete sample code is provided below:

The Code is as follows:
<% @ Page language = "java" import = "java. util. *" pageEncoding = "UTF-8" %>
<%
String path = request. getContextPath ();
String basePath = request. getScheme () + ": //" + request. getServerName () + ":" + request. getServerPort () + path + "/";
%>
<! DOCTYPE html>
<Html>
<Head>
<Title> Scale and upload images using Canvas and File APIs </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 = "August 8, 2013, renfufei@qq.com">
<Script src = "http://code.jquery.com/jquery-1.7.1.min.js"> </script>
<Script>
// Parameter, maximum height
Var MAX_HEIGHT = 100;
// Rendering
Function render (src ){
// Create an Image object
Var image = new Image ();
// Bind the load event processor and run it after loading.
Image. onload = function (){
// Obtain the canvas DOM object
Var canvas = document. getElementById ("myCanvas ");
// If the height exceeds the standard
If (image. height> MAX_HEIGHT ){
// Proportional scaling like width * =
Image. width * = MAX_HEIGHT/image. height;
Image. height = MAX_HEIGHT;
}
// Obtain the 2d environment object of the canvas,
// You can understand that Context is the administrator and canvas is the house.
Var ctx = canvas. getContext ("2d ");
// Canvas clear screen
Ctx. clearRect (0, 0, canvas. width, canvas. height );
// Reset the canvas width and height
Canvas. width = image. width;
Canvas. height = image. height;
// Draw the image to the canvas
Ctx. drawImage (image, 0, 0, image. width, image. height );
//!!! Note: The image is not added to the dom.
};
// Set the src attribute, which is automatically loaded by the browser.
// Remember that you must bind an event before setting the src attribute. Otherwise, synchronization may fail.
Image. src = src;
};
// Load the image file (url path)
Function loadImage (src ){
// Filter out non-image files
If (! Src. type. match (/image .*/)){
If (window. console ){
Console. log ("the selected file type is not an image:", src. type );
} Else {
Window. confirm ("only image files can be selected ");
}
Return;
}
// Create a FileReader object and call the render function to complete rendering.
Var reader = new FileReader ();
// Bind the load event automatic callback function
Reader. onload = function (e ){
// Call the preceding render Function
Render(e.tar get. result );
};
// Read the file content
Reader. readAsDataURL (src );
};
// Upload the image, jQuery version
Function sendImage (){
// Obtain the canvas DOM object
Var canvas = document. getElementById ("myCanvas ");
// Obtain Base64 encoded image data in the format of a string
// "Data: image/png; base64," must be removed from the client or server, and the subsequent parts can be directly written into the file.
Var dataurl = canvas. toDataURL ("image/png ");
// Encode the URI for security purposes
// Data % 3 Aimage % 2 Fpng % 3Bbase64% 2C start
Var imagedata = encodeURIComponent (dataurl );
// Var url = $ ("# form"). attr ("action ");
// 1. If the form is not easy to process, you can use a hidden field to set the request address.
// <Input type = "hidden" name = "action" value = "receive. jsp"/>
Var url = $ ("input [name = 'action']"). val ();
// 2. You can also directly obtain the attributes of a dom object.
// <Input id = "imageaction" type = "hidden" action = "receive. jsp">
// Var url = $ ("# imageaction"). attr ("action ");
// Because it is a string, the server needs to transcode the data and write files.
// Individual conventions, all http parameter names are in lowercase
Console. log (dataurl );
// Console. log (imagedata );
Var data = {
Imagename: "myImage.png ",
Imagedata: imagedata
};
JQuery. ajax ({
Url: url,
Data: data,
Type: "POST ",
// Expected Return Value Type
DataType: "json ",
Complete: function (xhr, result ){
// Console. log (xhr. responseText );
Var $ tip2 = $ ("# tip2 ");
If (! Xhr ){
$ Tip2.text ('network connection failed! ');
Return false;
}
Var text = xhr. responseText;
If (! Text ){
$ Tip2.text ('network error! ');
Return false;
}
Var json = eval ("(" + text + ")");
If (! Json ){
$ Tip2.text ('parsing error! ');
Return false;
} Else {
$ Tip2.text (json. message );
}
// Console. dir (json );
// Console. log (xhr. responseText );
}
});
};
Function init (){
// Obtain the DOM Element Object
Var target = document. getElementById ("drop-target ");
// Stop dragover (drag to the top of the DOM element) event Transmission
Target. addEventListener ("dragover", function (e) {e. preventDefault () ;}, true );
// Drag and release the mouse event
Target. addEventListener ("drop", function (e ){
// Block default events and event Propagation
E. preventDefault ();
// Call the previous image loading function. The parameter is the first file of the dataTransfer object.
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> Scale and upload images using Canvas and File APIs <P> drag a picture from the folder to the box below, canvas and JavaScript are automatically scaled. </p>
<Div>
<Input type = "text" id = "maxheight" value = "100"/>
<Button id = "setheight"> set the maximum image height </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; "> drag the image file here... </div>
<Div>
<Div>
<Button id = "btnsend"> upload </button> <span id = "tip2" style = "padding: 8px 0; color: # f00;"> </span>
</Div>
</Div>
<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>

Server Page, receive. jsp

The Code is as follows:
<% @ 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" %>
<%!
// This file:/receive. jsp
// Image storage path
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;
//
// Write to file
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)
{
// Adjust abnormal data
Data [I] + = 256;
}
}
//
Return data;
}
%>
<%
String path = request. getContextPath ();
String basePath = request. getScheme () + ": //" + request. getServerName () + ":" + request. getServerPort () + path + "/";
%>
<%
// If it is IE, you need to set it to text/html; otherwise, the download will pop up.
// 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 ){
// The data is too short and obviously unreasonable
Message = "Upload Failed, data is too short or does not exist ";
} Else {
// Remove unreasonable data at the beginning
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 = "uploaded successfully, parameter length:" + len2 + "character, parsed file size:" + len + "Byte ";
}
// Background Printing
System. out. println ("message =" + message );
%>
{
"Message": "<% = message %> ",
"Success": <% = success %>
}

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.