How should I crop an image at client side using jcrop and upload it?
Seahorsepip's answer is fantastic. I made a lot of improvements on the non-fallback answer.
http://jsfiddle.net/w1Lh4w2t/
I would recommend not doing that strange hidden png thing, when an Image object works just as well (so long as we're not supporting fallbacks).
var jcrop_api;
var canvas;
var context;
var image;
var prefsize;
Though even then we are, you're better off getting that data out of the canvas at the end and putting it in that field only at the end.
function loadImage(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function(e) {
image = new Image();
image.src = e.target.result;
validateImage();
}
reader.readAsDataURL(input.files[0]);
}
}
But, if you want more functions than just crop, if we attach the jcrop to an inserted canvas (which we destroy with the jcrop on refresh). We can easily do anything we can do with a canvas, then validateImage() again and have the updated image visible in place.
function validateImage() {
if (canvas != null) {
image = new Image();
image.src = canvas.toDataURL('image/png');
}
if (jcrop_api != null) {
jcrop_api.destroy();
}
$("#views").empty();
$("#views").append("<canvas id=\"canvas\">");
canvas = $("#canvas")[0];
context = canvas.getContext("2d");
canvas.width = image.width;
canvas.height = image.height;
context.drawImage(image, 0, 0);
$("#canvas").Jcrop({
onSelect: selectcanvas,
onRelease: clearcanvas,
boxWidth: crop_max_width,
boxHeight: crop_max_height
}, function() {
jcrop_api = this;
});
clearcanvas();
}
Then on submit we submit any pending operations, like applyCrop() or applyScale(), adding data into hidden fields for fallback stuff, if we have those things needed. We then have a system we can easily just modify the canvas, in any way, then when we submit the canvas data gets sent properly.
function applyCrop() {
canvas.width = prefsize.w;
canvas.height = prefsize.h;
context.drawImage(image, prefsize.x, prefsize.y, prefsize.w, prefsize.h, 0, 0, canvas.width, canvas.height);
validateImage();
}
The canvas is added to a div views.
<div id="views"></div>
To catch the attached file in PHP (drupal), I used something like:
function makeFileManaged() {
if (!isset($_FILES['croppedfile']))
return NULL;
$path = $_FILES['croppedfile']['tmp_name'];
if (!file_exists($path))
return NULL;
$result_filename = $_FILES['croppedfile']['name'];
$uri = file_unmanaged_move($path, 'private://' . $result_filename, FILE_EXISTS_RENAME);
if ($uri == FALSE)
return NULL;
$file = File::Create([
'uri' => $uri,
]);
$file->save();
return $file->id();
}
Client-Side Image Manipulation (Cropping)
Basically I would go this way:
- Load your image into a
<canvas>
- Crop the Image: http://www.html5canvastutorials.com/tutorials/html5-canvas-image-crop/
- Save a image from the canvas: http://www.html5canvastutorials.com/advanced/html5-canvas-save-drawing-as-an-image/
Here is a very good tutorial.
Disclaimer: I haven't tested this yet, but I heard that this way work.
Also use background-size:cover;
or background-size:contain;
to get around nasty dimension problems.
Upload and crop image before sending it to the server
jcrop
Jcrop is the quick and easy way to add image cropping functionality to your web application. It combines the ease-of-use of a typical jQuery plugin with a powerful cross-platform DHTML cropping engine that is faithful to familiar desktop graphics applications.
Cropping on server side vs cropping on client and sending base64 string?
I cannot speak about specific implementation performance or file size limits, but I am fairly certain that the desired approach here would be having both client- and server-side cropping, implemented thusly:
- If client is able to, crop it client-side
- Client sends to server whatever it's got (cropped if able to crop, uncropped otherwise)
- Server inspects what it received. If dimensions are greater than accepted, crop it server-side.
This is because even if you decided to implement client-side only, you would be a fool to trust that you'll never receive noncompliant data from your users. Since you're forced by that fact of life to make server-side validation anyway, that is a great opportunity to transparently crop big images, ensuring compliance regardless of the client's capabilities.
I wouldn't worry about client-side performance. 1 or 2 seconds of non-responsiveness when sending the picture wouldn't kill anyone.
About maximum file size, this is also not an issue in this approach, because you ensure the client sends the smaller version it can send. If it cannot crop and the image is too big, it won't be able to send it to you anyway.
Cropping images client side through browser with JavaScript
You can do this by loading the image into a Canvas element and then manipulating the Canvas
Basic tutorial here
http://www.w3schools.com/html/html5_canvas.asp
(plenty more available)
Related Topics
Change CSS Properties on Click
Detect CSS Transitions Using JavaScript (And Without Modernizr)
Access CSS File Contents via JavaScript
Get the Size of a CSS Background Image Using JavaScript
How to Check If CSS Value Is Supported by the Browser
Google Maps Not Rendering Completely on Page
Combination of Animation and Transition Not Working Properly
Why Is Element Not Being Shown Before Alert
Convert Dropdown to Selection Boxes with Color and Trigger Drop Down Action
Unable to Scroll in Scrollview
Mobile Safari on iOS Crashes on Big Pages
Add CSS Rule via Jquery for Future Created Elements
Disable Underline for Lowercase Characters: G Q P J Y
"Force Reflow" in CSS Transitions in Bootstrap
Full Height of a HTML Element (Div) Including Border, Padding and Margin
Run Greasemonkey Script on the Same Page, Multiple Times
Why Is My Asynchronous Function Returning Promise { ≪Pending≫ } Instead of a Value