Initial settings
As it comes to a jQuery plugin we need the call to the library somewhere in our HTML. In addition, we will also need to include the jCrop source file with its required style sheet and images.
<link href="css/jquery.Jcrop.css" rel="stylesheet" type="text/css" />
<script src="js/jquery.min.js"></script>
<script src="js/jquery.Jcrop.js"></script>
This way you can already use jCrop in its most basic form:
<img src="imagem.jpg" width="634" height="340" id="jcrop" />
<script type="text/javascript">
$(function(){
$('#jcrop').Jcrop();
});
</script>
In the above example, ‘#jcrop’
is the ID attribute of the Crop target image. You can use any type of jQuery selector (classes, sub-elements etc.) by applying the Crop frontend to various img elements.
The plugin works only on the client, on the application interface. Crop itself has to be done on the server.
Processing Crop with PHP
First let’s understand how jCrop works. Its marking method in the image returns an array with the dimensions and positioning of Crop. It has some events, here we will use the two main: onChange and onSelect. onChange executes any function at the time the markup is changed and onSelect executes any function at the time the selection is in progress.
Therefore, we will use, for now, the function exibePreview in both cases. What it does is update a preview of the final Crop result, and store variables for upload and processing on the server.
function exibePreview( c )
{
// c.x, c.y, c.x2, c.y2, c.w, c.h
};
The function receives the array c, the one with the dimensions and coordinates of Crop. The values of the array are:
w width (width) of Crop
h height (height) of Crop
X1 and x2 horizontal Crop positions in the image
Y1 and Y2 vertical Crop positions in the image
Note that this is where jCrop’s work ends. Values should be processed in PHP. In our example, as I mentioned earlier, the displayPreview function will record the positions in inputs of type Hidden in the shipping form.
function exibePreview( c )
{
// campos hidden que armazenam os valores
$('#x').val(c.x);
$('#y').val(c.y);
$('#x2').val(c.x2);
$('#y2').val(c.y2);
$('#w').val(c.w);
$('#h').val(c.h);
};
In addition, it must update the preview of the cropped image. For this we will need the original image size. If you are using the same image format, just use the same values always. In our case, as the image is sent via form, we use the getimagesize function of php to return the width (index 0 of the return array) and the height (index 1). They are necessary to calculate the positioning of Crop. The idea is to create a div with Crop dimensions, masking the original image.
function exibePreview(c)
{
var rx = 100 / c.w;
var ry = 100 / c.h;
// atualiza CSS do preview para refletir o tamanho da imagem enviada
// e o posicionamento do crop
$('#preview').css({
width: Math.round(rx * <?php echo $imagesize[0]; ?>) + 'px',
height: Math.round(ry * <?php echo $imagesize[1]; ?>) + 'px',
marginLeft: '-' + Math.round(rx * c.x) + 'px',
marginTop: '-' + Math.round(ry * c.y) + 'px'
});
// campos hidden que armazenam os valores
$('#x').val(c.x);
$('#y').val(c.y);
$('#x2').val(c.x2);
$('#y2').val(c.y2);
$('#w').val(c.w);
$('#h').val(c.h);
}
With the full Preview function, we can now update our jCrop call:
$('#jcrop').Jcrop({
onChange: exibePreview,
onSelect: exibePreview,
aspectRatio: 1
});
Note the property aspectRatio, used to tie width and height of Crop, maintaining the ratio.
Everything’s OK at the front. Below you check the upload form code and the post-upload image processing script (validation and resizing to avoid giant Crop files).
<form name="frm-jcrop" id="frm-jcrop" method="post" action="index.php" enctype="multipart/form-data">
<p>
<label>Envie uma imagem:</label>
<input type="file" name="imagem" id="imagem" />
<input type="submit" value="Enviar" />
</p>
</form>
// processa arquivo
$imagem = isset( $_FILES['imagem'] ) ? $_FILES['imagem'] : NULL;
$img = '';
// verifica se arquivo foi enviado para o servidor
if( $imagem['tmp_name'] )
{
// move arquivo para o servidor
if( move_uploaded_file( $imagem['tmp_name'], $imagem['name'] ) )
{
include( 'm2brimagem.class.php' );
$oImg = new m2brimagem( $imagem['name'] );
if( $oImg->valida() == 'OK' )
{
// redimensiona imagem para evitar arquivos grandes
$oImg->redimensiona( '400', '', '' );
$oImg->grava( $imagem['name'] );
// retorna dimensões da imagem e configura variáveis para o jCrop
$imagesize = getimagesize( $imagem['name'] );
$img = '<img src="'.$imagem['name'].'" id="jcrop" '.$imagesize[3].' />';
$preview = '<img src="'.$imagem['name'].'" id="preview" '.$imagesize[3].' />';
}
else
{
// imagem inválida, exclui do servidor
unlink( $imagem['name'] );
}
}
}
It’s almost ready. We have a form to upload the image, and all the javascript that will process Crop and update our preview. Missing the PHP code that will actually crop the sent image. For this we will use the class m2brimagem (read more about it here).
The processing will be done via AJAX/post, just to expedite the return to the user, but nothing prevents you from doing Crop in a resubmission form.
$('#btn-crop').click(function(){
$.post( 'crop.php', {
img:img,
x: $('#x').val(),
y: $('#y').val(),
w: $('#w').val(),
h: $('#h').val()
}, function(){
$('#div-jcrop').html( '<img src="'+img+'?'+Math.random()+'" width ="'+$('#w').val()+'" height ="'+$('#h').val()+'" />' );
});
return false;
});
Once processed, our form will display a new screen, with the option to crop and save a piece of the submitted image. In the example you can observe that, in addition to the image and the interface for Crop, we also show two additional windows: the preview, already commented previously; and a small debug, displaying the information and coordinates in real time (all this updated via displayPreview).
When clicking the save button, the user executes, via AJAX, the script below, once again using the m2brimagem class for processing. The script takes as parameter the starting point X and Y of Crop, in addition to its width and height, and creates the cropped version of the original image. After execution, our img element is updated. As in this case the final image has the same name as the original image, we use the "?" with a random number (Math.Random()) to avoid caching (this tip is very nice for image uploading systems).
if( $_SERVER['REQUEST_METHOD'] == 'POST' )
{
include( 'm2brimagem.class.php' );
$oImg = new m2brimagem( $_POST['img'] );
if( $oImg->valida() == 'OK' )
{
$oImg->posicaoCrop( $_POST['x'], $_POST['y'] );
$oImg->redimensiona( $_POST['w'], $_POST['h'], 'crop' );
$oImg->grava( $_POST['img'] );
}
}
exit;
Other options
Maybe everything seems a little confusing looking at the codes so separately. Download the examples that you will understand better. On the plugin’s website you will find the complete documentation, in English, as well as other examples. One option I use a lot is to specify fixed width and height. When the user uploads an avatar, for example, it is worth limiting the size in jCrop (or else doing something proportional). The minSize and maxSize properties delimit the minimum and maximum Crop area.
$('#jcrop').Jcrop({
onChange: exibePreview,
onSelect: exibePreview,
minSize : [ 200, 200 ],
maxSize : [ 200, 200 ],
allowResize : false,
addClass : 'custom'
});
In the above example Crop will always have 200 200 pixels in dimension. In addition, we configure the allowResize property with false, to avoid resizing the selection. Another cool property is addClass, to define a custom style in the selection. In the example below the line gets a solid edge instead of the dotted.
.custom .jcrop-vline, .custom .jcrop-hline {
background: #FF3366;
}
Source of the answer tutorial
I don’t know if it’s possible to do this with Javascript. I think the most you can do is take the dimensions you want (using JS) of the image and send it to the server to process it. But I’m not sure, better wait for someone who knows more to say.
– gabrielhof
Yes, @gabrielhof. But the question is how to pass the coordinates to PHP.
– bfavaretto
Just as a reference, that other library allows you to crop an image in arbitrary formats, not only rectangular. Here is a example in jsFiddle
– mgibsonbr