We have received several inquiries for the last time from our readers with a question – how to upload photos to website. I think that this is an interesting question, and, I decided to lift the veil of this question. But, I think that the basic file upload is a bit boring thing, so, I decided to add an important feature – Cropping. It should be more attractive. Moreover, we are going to use HTML5 FileReader in order to perform cropping with Jcrop (jquery library) at client size. That will get rid of unnecessary steps. In the result – we should get 3-step process: select file -> crop -> upload. During selecting a file, we will check for the file type and size (in order to avoid huge files). Finally, when everything is ready and we have uploaded the cropped image – we will accept (upload) this file into our website (into certain folder). Please pay attention, that GD library is required to process images. If you are ready – let’s start.
It is the very time to test our demo and download the sources:
[sociallocker]
[/sociallocker]
Step 1. HTML
Our first step is html markup. first, we have to put styles and scripts in the HEAD section:
2 | <link href="css/main.css" rel="stylesheet" type="text/css" /> |
3 | <link href="css/jquery.Jcrop.min.css" rel="stylesheet" type="text/css" /> |
5 | <script src="js/jquery.min.js"></script> |
6 | <script src="js/jquery.Jcrop.min.js"></script> |
7 | <script src="js/script.js"></script> |
And now, in the BODY section we can put our form:
03 | <form id="upload_form" enctype="multipart/form-data" method="post" action="upload.php" onsubmit="return checkForm()"> |
05 | <input type="hidden" id="x1" name="x1" /> |
06 | <input type="hidden" id="y1" name="y1" /> |
07 | <input type="hidden" id="x2" name="x2" /> |
08 | <input type="hidden" id="y2" name="y2" /> |
09 | <h2>Step1: Please select image file</h2> |
10 | <div><input type="file" name="image_file" id="image_file" onchange="fileSelectHandler()" /></div> |
11 | <div class="error"></div> |
13 | <h2>Step2: Please select a crop region</h2> |
16 | <label>File size</label> <input type="text" id="filesize" name="filesize" /> |
17 | <label>Type</label> <input type="text" id="filetype" name="filetype" /> |
18 | <label>Image dimension</label> <input type="text" id="filedim" name="filedim" /> |
19 | <label>W</label> <input type="text" id="w" name="w" /> |
20 | <label>H</label> <input type="text" id="h" name="h" /> |
22 | <input type="submit" value="Upload" /> |
I hope that all is clear at this step – this is usual upload form, with hidden and visible fields, once we have selected an image, we will see second step (crop). Once we have cropped necessary area, we can Upload our result.
Step 2. CSS
Now, I would like to give you CSS styles to stylize our form:
css/main.css
02 | background-color: #DDDDDD; |
03 | border-radius: 10px 10px 0 0; |
12 | background: -moz-linear-gradient(#ffffff, #f2f2f2); |
13 | background: -ms-linear-gradient(#ffffff, #f2f2f2); |
14 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(100%, #f2f2f2)); |
15 | background: -webkit-linear-gradient(#ffffff, #f2f2f2); |
16 | background: -o-linear-gradient(#ffffff, #f2f2f2); |
17 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f2f2f2'); |
18 | -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f2f2f2')"; |
19 | background: linear-gradient(#ffffff, #f2f2f2); |
21 | .bbody h2, .info, .error { |
39 | border: 1px solid #CCCCCC; |
46 | display: inline-block; |
50 | border: 1px solid #bbb; |
52 | -webkit-box-shadow: inset 0 0 1px 1px #f6f6f6; |
53 | box-shadow: inset 0 0 1px 1px #f6f6f6; |
55 | font: bold 12px/1 "helvetica neue", helvetica, arial, sans-serif; |
58 | text-shadow: 0 1px 0 #fff; |
61 | input[type=submit]:hover { |
63 | -webkit-box-shadow: inset 0 0 1px 1px #eaeaea; |
64 | box-shadow: inset 0 0 1px 1px #eaeaea; |
68 | input[type=submit]:active { |
70 | -webkit-box-shadow: inset 0 0 1px 1px #e3e3e3; |
71 | box-shadow: inset 0 0 1px 1px #e3e3e3; |
Step 3. JS
Our next step – is javascript. Please review the result code (my comments are below the code):
js/script.js
02 | function bytesToSize(bytes) { |
03 | var sizes = ['Bytes', 'KB', 'MB']; |
04 | if (bytes == 0) return 'n/a'; |
05 | var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); |
06 | return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i]; |
09 | function checkForm() { |
10 | if (parseInt($('#w').val())) return true; |
11 | $('.error').html('Please select a crop region and then press Upload').show(); |
15 | function updateInfo(e) { |
24 | function clearInfo() { |
25 | $('.info #w').val(''); |
26 | $('.info #h').val(''); |
29 | var jcrop_api, boundx, boundy; |
30 | function fileSelectHandler() { |
32 | var oFile = $('#image_file')[0].files[0]; |
36 | var rFilter = /^(image\/jpeg|image\/png)$/i; |
37 | if (! rFilter.test(oFile.type)) { |
38 | $('.error').html('Please select a valid image file (jpg and png are allowed)').show(); |
42 | if (oFile.size > 250 * 1024) { |
43 | $('.error').html('You have selected too big file, please select a one smaller image file').show(); |
47 | var oImage = document.getElementById('preview'); |
49 | var oReader = new FileReader(); |
50 | oReader.onload = function(e) { |
52 | oImage.src = e.target.result; |
53 | oImage.onload = function () { |
55 | $('.step2').fadeIn(500); |
57 | var sResultFileSize = bytesToSize(oFile.size); |
58 | $('#filesize').val(sResultFileSize); |
59 | $('#filetype').val(oFile.type); |
60 | $('#filedim').val(oImage.naturalWidth + ' x ' + oImage.naturalHeight); |
62 | if (typeof jcrop_api != 'undefined') { |
65 | $('#preview').width(oImage.naturalWidth); |
66 | $('#preview').height(oImage.naturalHeight); |
68 | setTimeout(function(){ |
80 | var bounds = this.getBounds(); |
90 | oReader.readAsDataURL(oFile); |
There are several common functions in the beginning: bytesToSize, checkForm, updateInfo and clearInfo. They are pretty easy. The next function (fileSelectHandler) is more complex, basically, this is the main function. When we have selected a file (I suppose – image file), we will check this file for Type and Size. You can see here a filter for image formats: png and jpg. Plus, we don’t need very large images, I think that 250kb is more than enough. Then, if everything is ok, we can read our selected file using FileReader::readAsDataURL (html5 function). And, once it has loaded, we can continue: we should display step2 with Preview and info section, and then – we have to initialize (or – reinitialize) Jcrop for our Preview image. This is how it works. Once we have cropped the image, we can click ‘Upload’ button in order to send result to the server.
Step 4. PHP
In this step – we have to accept (and upload) our result photo. I prepared next useful PHP function for you:
upload.php
01 | function uploadImageFile() { |
02 | if ($_SERVER['REQUEST_METHOD'] == 'POST') { |
03 | $iWidth = $iHeight = 200; |
07 | if (! $_FILES['image_file']['error'] && $_FILES['image_file']['size'] < 250 * 1024) { |
08 | if (is_uploaded_file($_FILES['image_file']['tmp_name'])) { |
10 | $sTempFileName = 'cache/' . md5(time().rand()); |
12 | move_uploaded_file($_FILES['image_file']['tmp_name'], $sTempFileName); |
14 | @chmod($sTempFileName, 0644); |
15 | if (file_exists($sTempFileName) && filesize($sTempFileName) > 0) { |
16 | $aSize = getimagesize($sTempFileName); |
18 | @unlink($sTempFileName); |
26 | $vImg = @imagecreatefromjpeg($sTempFileName); |
31 | $vImg = @imagecreatefrompng($sTempFileName); |
34 | @unlink($sTempFileName); |
38 | $vDstImg = @imagecreatetruecolor( $iWidth, $iHeight ); |
40 | imagecopyresampled($vDstImg, $vImg, 0, 0, (int)$_POST['x1'], (int)$_POST['y1'], $iWidth, $iHeight, (int)$_POST['w'], (int)$_POST['h']); |
42 | $sResultFileName = $sTempFileName . $sExt; |
44 | imagejpeg($vDstImg, $sResultFileName, $iJpgQuality); |
45 | @unlink($sTempFileName); |
46 | return $sResultFileName; |
53 | $sImage = uploadImageFile(); |
54 | echo '<img src="'.$sImage.'" />'; |
As you see – we have to check for image size and format at the server’s side too. In the result – we will get double protection (at user side and server side) from unwanted files. Once we have uploaded the image (using move_uploaded_file) – we can crop it (using GD’s functions: imagecreatefromjpeg, imagecreatetruecolor and imagecopyresampled), and – turn result into image file using ‘imagejpeg’ function. Please pay attention – that in the result we will get a small image (which is onle 200×200), so, beside cropping, we also resize the image. I selected next desired size for all incoming photos: 200×200 (this is a good format for .. profile’s avatars as example). Finally – we can display this image on the screen. That’s all.
Conclusion
We have just created own HTML5 Image uploader with Jcrop. I hope that you like it. It would be nice of you to share our materials with your friends. Good luck and welcome back!