Closed keepdream closed 12 years ago
Hi. To integrate jcrop i used a done callback. This means i add jcrop only after successful upload. In general its look like this: on done you have data object. Data.result is an array of files' information returned from server. For each file (image) you need to create separate cropbox, and initialize jcrop plugin for each cropbox after image was loaded. Than post that data to server and handle croping of image on server side. Well, it's my solution, but there are many another ways.
Code:
var cropbox_indx = 0, //index of cropbox
img_data = {}, // keeps uploaded image data
crop_w = 150,
crop_h = 125;
$('#fileupload').fileupload({
done: function (e, data) {
cropbox_indx += 1;
$.each(data.result, function (index, file) {
if (data.error == undefined && file.error == undefined){
// show uploaded images and initialize cropbox
var id_upload = 'upload'+cropbox_indx,
id_img = 'cropbox'+cropbox_indx,
img_container = $('<div/>').attr({'id': id_upload, 'class': 'image'}).appendTo($('#files_container')),
img = $('<img/>').attr({'id': id_img, 'class': 'cropbox', 'src': file.url, 'style': 'display: none'}).appendTo($('#'+id_upload));
img.load(function(){
img_data[cropbox_indx] = {f_name: file.name, dimensions: {crop_w: crop_w, crop_h: crop_h}, coords: 0};
crop(id_img, img, cropbox_indx, img_data); // this function is below
img_container.css({'width': img.width, 'height': img.height});
});
}
});
}
});
// initialize cropbox for each image
function crop(id_img, img, cropbox_indx, img_data){
var proportion_coef = img_data[cropbox_indx].dimensions.crop_w/img_data[cropbox_indx].dimensions.crop_h,
cx = img.width()/2,
cy = img.height()/2;
if (img.width() >= img.height()){
var h_crop = img.height()*0.7,
w_crop = h_crop*proportion_coef,
x = cx - w_crop/2, //this coords used to set default selection
y = cy - h_crop/2,
x2 = x + w_crop,
y2 = y + h_crop;
} else {
w_crop = img.width()*0.7;
h_crop = w_crop/proportion_coef;
x = cx - w_crop/2;
y = cy - h_crop/2;
x2 = x + w_crop;
y2 = y + h_crop;
}
var coords = {};
coords = {'x': x, 'y': y, 'w': (x2 - x), 'h': (y2 - y)};
img_data[cropbox_indx].coords = coords;
$("#"+id_img).Jcrop({
onSelect: function(c){
coords.x = c.x;
coords.y = c.y;
coords.w = c.w;
coords.h = c.h;
img_data[cropbox_indx].coords = coords;
},
aspectRatio: proportion_coef,
bgOpacity:.2,
boxWidth: 300,
boxHeight: 300,
setSelect: [x, y, x2, y2]
});
}
after this you need to post data to server:
$('#crop').click(function(){
var img_data_arr = [];
$.each(img_data, function(key, value){
var coords_arr = [],
dimensions_arr = [];
$.each(value.coords, function(key, value){
coords_arr.push('"'+key+'"'+':'+value);
});
$.each(value.dimensions, function(key, value){
dimensions_arr.push('"'+key+'"'+':'+value);
});
var id_json = '"'+key+'"'+':{"coords":{'+coords_arr.join(',')+'},"f_name":"'+value.f_name+'","dimensions":{'+dimensions_arr.join(',')+'}}';
img_data_arr.push(id_json);
});
var img_data_json = '{'+img_data_arr.join(',')+'}';
$.post($('#fileupload').attr('action'), {img_data_json: img_data_json}, function(res){
var imgs = $.parseJSON(res);
});
});
and on server i rewrite thumbnail, created by upload handler class
public function crop(){
$img_data = json_decode(stripslashes($_POST['img_data_json']));
$imgs = array();
foreach ($img_data as $key => $value) {
$img = $this->options['upload_dir'].$value->f_name;
$thumb = $this->options['image_versions']['thumbnail']['upload_dir'].$value->f_name;
if (exec('convert')){
exec("convert $img -crop {$value->coords->w}x{$value->coords->h}+{$value->coords->x}+{$value->coords->y}".
" -resize {$value->dimensions->crop_w}x{$value->dimensions->crop_h} $thumb");
} else {
$new_img = @imagecreatetruecolor($value->dimensions->crop_w, $value->dimensions->crop_h);
$src_img = @imagecreatefromjpeg($img);
list($img_width, $img_height) = @getimagesize($img);
$write_image = 'imagejpeg';
@imagecopyresampled(
$new_img,
$src_img,
0, 0, $value->coords->x, $value->coords->y,
$value->dimensions->crop_w,
$value->dimensions->crop_h,
$value->coords->w,
$value->coords->h
);
$write_image($new_img, $thumb);
//Free up memory (imagedestroy does not delete files):
@imagedestroy($src_img);
@imagedestroy($new_img);
}
$image = array(
'name' => $value->f_name,
'image_url' => $this->options['upload_url'].$value->f_name,
'thumbnail_url' => $this->options['image_versions']['thumbnail']['upload_url'].$value->f_name
);
$imgs[] = $image;
}
echo json_encode($imgs);
}
You can add jcrop functionality even before uploading, but you'll need to handle scaling of thumbnail and calculating right coords by yourself and you'll have some more troubles.
Thanks !
I'm sorry for reopening a closed issue, but I'm trying to make jcrop work and even if you explained everything very well I still can't make it work. Can you explain it a little bit more? I'm using the template from the example and I added a button called crop. I auto upload the files, so the user can see only the download template. I also change the name of the files. I don't understand where my error is. Thank you very much.
From your question i didn't understand what exactly not working.
But you need to know, that every cropbox must have uniqe id and uniqe initialization of Jcrop. Jcrop for every image (cropbox) must be initialized AFTER the image appear (jquery load event) on the page. Sorry for my English...
Thank you very much for your quick answer. Yes, I know that every cropbox must have unique id. So, I want to make something like this: the user loads an image, then he can see the thumb other things and two buttons, one is the delete button and the other one is the crop button. when the user clicks on the crop button I would like to use the jquery-ui crop (with the dialog ) to show the image that he can crop, then the user crops the image clicks on a save or crop button and the image now is the one that he croped, and he can see that image in the list with the other images (the list = the template download from the jquery-file-upload). Sorry for my English too...
anyway, in your example, jcrop is initialized after the image appear on done event, no? maybe I'm not passing the right things to the function. what should I have inside my crop button? Maybe I undestood everything wrong... :( It's the first time that I use Jcrop...
Well, when the dialog is opened, you need to append an image (original image, not thumbnail) to some block in dialog. Then on $('your_original_image).load(function(){ ... }) event initialize Jcrop with needed parametrs (for example 'function crop' in second post calles only on img.load(). img was created and appended to some block in row before) . When user choose crop region and press 'ok', send coordinates to server and handle croping on server.
Done calls ones, after image uploaded and in my case it works as i need, but you need to initialize jcrop later, for example, when crop button is clicked or, better, on dialog open event. For example when crop is clicked the appropriate image is appended to dialog (it is hidden on this moment), and on image load event the dialog opens and Jcrop initializes
$("#headPhotoId").fileupload({ autoUpload: false, type:type, url: url, acceptFileTypes: /(.|\/)(gif|jpe?g|png)$/i, formData:formData }).on('fileuploadadd', function (e, data){ imgData = data; }).on('fileuploadsend',function(e, data){ data.url +="?x2="+x2+"&w="+w; console.info("fileuploadsend"); });
$("#uploadHeadPhotoBtnId").click(function(){ //$("#headPhotoId").file(); imgData.submit(); });
Hi can you provide an example of a succesfull Jcrop (or similar) plugin integration ? I looked at the other topics but there wasn't a complete explanation.
Thanks
KD