Crop and upload HTML5 local images,
Recently, a project was created. One feature that needs to be implemented in this project is: User-Defined Avatar (the user selects an image locally, crop the image locally to a size that meets the system requirements ). The requirement for this function is: the Avatar is first cut into a square. If the selected image is smaller than the size required by the specified avatar, the entire image will be taken as the Avatar. If the size is greater than the specified size, you can select the area to be cropped. Click OK to send the cropped image data to the server and save the image data as a file at the backend.
The knowledge involved in completing the above functions includes ajax, canvas, and files interfaces in html5. I encapsulated the code to implement this function into four modules: ajax. js, preview. js, shear. js, and customerImg. js.
Ajax. js: used to send ajax requests.
Preview. js: used for image preview
Shear. js: Used to crop images
Customer. js: custom avatar. Introduce ajax. js, preview. js and shear. js in this module.
I use webpack for packaging. I also use jquery and jquery-ui.
I have extracted this feature from this project. The following is the detailed code for this function.
1. HTML code
<Div class = "m-warp" id = "warp"> <div class = "item"> <input type = "file" name = "img" id = "img" hidden> <label for = "img"> select an image </label> </div> <div class = "item clearfix"> <div class = "col-1"> <div class = "preview" id = "preview"> <div class = "mask"> </div> <canvas class = "cvsMove" id = "cvsMove"> </ canvas> </div> <div class = "thum col-2 col"> <p> preview </p> <p class =" f-text-l f-marTop-20 "> <button class =" shear "id =" submit "> OK </button> </p> </div> </div>
2. CSS code
.clearfix:after{ content: ""; display: block; clear: both; height: 0; overflow: hidden; visibility: hidden;}img{
vertical-align: middle;
max-width:100%
}.m-warp{ width: 800px;}.item{ margin-top: 20px;}.col{ float: left;}.col-1{ position: relative; width: 450px; height: 450px; outline: 1px solid #333;}.preview{ display: inline-block;}.col-2{ width: 300px; margin-left: 50px;}label{ display: block; text-align: center; width: 100px; font-size: 16px; color: #fff; background-color: #888888; height: 30px; line-height: 30px;}.mask{ position: absolute; z-index: 1; top:0; left: 0; bottom: 0; right: 0; background-color: rgba(0,0,0,.4);}.cvsMove{ position: absolute; z-index: 2; outline: 2px dotted #333; cursor: move; display: none;}
The running results of css and html are as follows:
3. js Code customerImg. js
Var $ = require ('jquery '); var ajax = require ('. /ajax. js '); var preview = require ('. /preview. js '); var shear = require ('. /shear. js ');/*** custom profile * @ constructor */function CustomerImg () {this. isSupport = null; this. previewBox = null; this. warp = null;}/*** entry * @ param warp operation region jquery node */CustomerImg. prototype. start = function (warp) {var info, me, warpBox; me = this; this. isSupport = this. _ isSupport (); If (! This. isSupport) {info = $ ('<p> your browser does not support user-defined portraits. You can change the User-Defined profile of a later browser </p> '); condition ('body'{.html (info); return this ;}// you can specify if (warp & warp. length> 0) {this. warp = warp;} else {return this;} // preview. start (warp, shear. start. bind (shear, warp); this. previewBox = warp. find ('# preview'); // confirm warp. find ('# submit '). unbind ('click '). on ('click', me. _ submit. bind (me) ;};/*** submit * @ private */CustomerImg. prototype. _ submit = function () {var cvsMove, data, fd; cvsMove = this. previewBox. find ('# cvsMove'); data = cvsMove [0]. toDataURL ('image/jpg ', 1); fd = {'customer': data}; ajax. upload (fd) ;};/*** determine whether custom profile pictures are supported * @ returns {boolean} * @ private */CustomerImg. prototype. _ isSupport = function () {var canvas, context; canvas = document. createElement ('canvas '); if (typeof FileReader === 'function' & canvas. getContext & canvas. toDataURL) {return true;} else {return false ;}}; var customerImg = new CustomerImg (); module. exports = customerImg;
Preview. js
/*** Created by star on April /3/7. */var $ = require ('jquery ');/***** Preview class * @ constructor */function Preview () {this. boxElem = null; this. callback = null; this. type = null;}/*** entry * @ param boxElem operation Region * @ param callback the callback Function After previewing */Preview. prototype. start = function (boxElem, callback) {var chooseFile, me; me = this; if (! BoxElem | boxElem. length <= 0) return this; this. boxElem = boxElem; if (typeof callback = 'function') {this. callback = callback;} if (this. _ isSupport () {chooseFile = boxElem. find ('input [type = "file"] '); chooseFile. on ('change', me. fileChange. bind (me) }};/*** select the image event handler * @ param event */Preview. prototype. fileChange = function (event) {var target, reader, file, me, type; target = event.tar get; me = This; file = target. files [0]; type = file. type; this. type = type; if (type! = 'Image/png '& type! = 'Image/jpg '& type! = 'Image/jpeg ') {alert ('file format incorrect'); return this;} reader = new FileReader (); if (file) {reader. readAsDataURL (file);} reader. onload = function () {me. show (reader) ;}};/*** displays the locally selected image * @ param reader fileReader object */Preview. prototype. show = function (reader) {var preView, img, me; preView = this. boxElem. find ('# preview'); img = preview. find ('# preImg'); me = this; if (img. length <= 0) {preView. append ($ ('');} img = preView. find ('# preImg'); // make sure that the image is loaded before calling back img. on ('load', function () {if (me. callback) {me. callback (me. type) ;}}); img. attr ('src', reader. result) ;};/*** support Preview * @ returns {boolean} * @ private */Preview. prototype. _ isSupport = function () {return typeof FileReader === 'function';}; var preview = new Preview (); module. exports = preview;
Shear. js
Var $ = require ('jquery '); // expose $ to the window because jquery-ui is used. Window. $ =$; require ('. /jquery-ui.min.js ');/*** cut * @ constructor */function Shear () {this. previewBox = null; this. cvsMove = null; this. maxW = 200; this. maxH = 200; this. thum = null; this. fileType = 'image/jpeg ';}/*** entry * @ param previewBox preview element parent element * @ param fileType specifies the type of the cropped image, for example: 'image/jpg '* @ returns {Shear} */Shear. prototype. start = function (previewBox, fileType) {if (! Arguments. length) return this; var me = this; this. previewBox = previewBox; if (fileType) {this. fileType = fileType;} this. thum = this. previewBox. find ('# thum'); this. cvsMove = this. previewBox. find ('# cvsMove'); this. showCanvas (); return this ;};/*** display canvas */Shear. prototype. showCanvas = function () {var preImg, h, w, me, cvsH, cvsW, rateH, rateW, naturalH, naturalW, preview; me = this; preImg = this. previewBox. find ('# preImg'); preview = this. previewBox. find ('# preview'); naturalH = preImg [0]. naturalHeight; naturalW = preImg [0]. naturalWidth; // display the canvas this. cvsMove. show (); // place the canvas in (0, 0) this. cvsMove. css ({"left": '0', 'top': '0'}); h = preImg. height (); w = preImg. width (); // specify that the size of the cropped image is 200px * 200px // ensure that the cropped image is not deformed if (h <this. maxH | w <this. maxW) {this. cvsMove [0]. width = cvsW = Math. min (h, w); this. cvsMove [0]. height = cvsH = Math. min (h, w);} else {this. cvsMove [0]. width = cvsW = this. maxW; this. cvsMove [0]. height = cvsH = this. maxH;} rateH = h/naturalH; rateW = w/naturalW; this. _ drawImg (preImg, cvsW/rateW, cvsH/rateH, cvsW, cvsH); // use the functions in jquery-ui to make canvas move this. cvsMove. draggable ({containment: "parent", drag: function (event, ui) {var left, top; left = ui. position. left; top = ui. position. top; // each time the canvas is moved, a new me image is drawn. _ drawImg (preImg, left/rateW, top/rateH, cvsW/rateW, cvsH/rateH, cvsW, cvsH );}})}; /*** display the image on the canvas * @ param myImg the image node to be displayed * @ param sx the starting point of the image on the original image x coordinate * @ param sy the starting point of the image on the original image y coordinate on * @ param sW width on the source image * @ param sH height on the source image * @ param dx x coordinate on the canvas * @ param dy start on the canvas y coordinate on * @ param dW width on the canvas * @ param dH height on the canvas * @ private */Shear. prototype. _ drawImg = function (myImg, sx, sy, sW, sH, dx, dy, dW, dH) {var cxt, thum, me; me = this; cxt = this. cvsMove [0]. getContext ('2d '); cxt. drawImage (myImg [0], sx, sy, sW, sH, dx, dy, dW, dH); thum = this. thum; // display the pattern on the canvas to the right side of thum. attr ('src', this. cvsMove [0]. toDataURL (me. fileType, 1 )). width (this. maxW ). height (this. maxH)}; var shear = new Shear (); module. exports = shear;
Ajax. js
Var $ = require ('jquery '); function Ajax () {}/*** upload image data */Ajax. prototype. upload = function (data) {$. ajax ({type: 'post', data: data, dataType: 'json', url: '/test/PHP/upload. php ', success: function (result) {if (result. status) {location. reload ();} else {alert (result. msg) ;}}) ;}; var ajax = new Ajax (); module. exports = ajax;
Finally, in another file, call the start method of the customerImg object.
var $ = require('jquery');var customerImg =require('./customerImg.js');customerImg.start($('#warp'));
The webpack configuration file is as follows:
var webpack = require('webpack');module.exports = { entry:{ 'customerImg':'./js/test.js', 'jQuery':['jquery'] }, output:{ filename:'[name].js', library:'jQuery', libraryTarget:'umd' }, plugins:[ new webpack.optimize.CommonsChunkPlugin({ name:'jQuery', filename:'jquery.js' }) ]};
Effect:
4. php code
if(!empty($_POST) && isset($_POST['customerImg'])){ $img = $_POST['customerImg']; $imgdata = explode(',', $img); $uniName = md5 ( uniqid ( microtime ( true ), true ) ); $a = file_put_contents('./../uploads/'.$uniName.'.jpg', base64_decode($imgdata[1]));}