jQuery image upload & crop
I was searching for a nice script with that i can upload and crop images.
I found a nice one @ http://www.webmotionuk.co.uk/php-jquery-image-upload-and-crop/ and made it cake ready ;)
So, i hope i can help you with my first Article!
Here we go:
I found a nice one @ http://www.webmotionuk.co.uk/php-jquery-image-upload-and-crop/ and made it cake ready ;)
So, i hope i can help you with my first Article!
Here we go:
Requirements
- PHP 4 or Higher (It has been tested on Version 5)
- PHP GD Library
- jQueryhttp://jquery.com/
- Image Area Select plugin -> http://odyniec.net/projects/imgareaselect/
Installation
Ok, now we must create a new Component called "JqImgcrop".
Let`s create a new file called "jq_imgcrop.php" in yourapp/controllers/components/ with following content:
Component Class:
Download code
<?php
class JqImgcropComponent extends Object {
function uploadImage($uploadedInfo, $uploadTo, $prefix){
$webpath = $uploadTo;
$upload_dir = WWW_ROOT.str_replace("/", DS, $uploadTo);
$upload_path = $upload_dir.DS;
$max_file = "34457280"; // Approx 30MB
$max_width = 800;
$userfile_name = $uploadedInfo['name'];
$userfile_tmp = $uploadedInfo["tmp_name"];
$userfile_size = $uploadedInfo["size"];
$filename = $prefix.basename($uploadedInfo["name"]);
$file_ext = substr($filename, strrpos($filename, ".") + 1);
$uploadTarget = $upload_path.$filename;
if((!empty($uploadedInfo)) && ($uploadedInfo["error"] == 0)) {
return false;
}
if (isset($uploadedInfo['name'])){
move_uploaded_file($userfile_tmp, $uploadTarget );
chmod ($uploadTarget , 0777);
$width = $this->getWidth($uploadTarget);
$height = $this->getHeight($uploadTarget);
// Scale the image if it is greater than the width set above
if ($width > $max_width){
$scale = $max_width/$width;
$uploaded = $this->resizeImage($uploadTarget,$width,$height,$scale);
}else{
$scale = 1;
$uploaded = $this->resizeImage($uploadTarget,$width,$height,$scale);
}
}
return array('imagePath' => $webpath.$filename, 'imageName' => $filename, 'imageWidth' => $this->getWidth($uploadTarget), 'imageHeight' => $this->getHeight($uploadTarget));
}
function getHeight($image) {
$sizes = getimagesize($image);
$height = $sizes[1];
return $height;
}
function getWidth($image) {
$sizes = getimagesize($image);
$width = $sizes[0];
return $width;
}
function resizeImage($image,$width,$height,$scale) {
$newImageWidth = ceil($width * $scale);
$newImageHeight = ceil($height * $scale);
$newImage = imagecreatetruecolor($newImageWidth,$newImageHeight);
$ext = strtolower(substr(basename($image), strrpos(basename($image), ".") + 1));
$source = "";
if($ext == "png"){
$source = imagecreatefrompng($image);
}elseif($ext == "jpg" || $ext == "jpeg"){
$source = imagecreatefromjpeg($image);
}elseif($ext == "gif"){
$source = imagecreatefromgif($image);
}
imagecopyresampled($newImage,$source,0,0,0,0,$newImageWidth,$newImageHeight,$width,$height);
imagejpeg($newImage,$image,90);
chmod($image, 0777);
return $image;
}
function resizeThumbnailImage($thumb_image_name, $image, $width, $height, $start_width, $start_height, $scale){
$newImageWidth = ceil($width * $scale);
$newImageHeight = ceil($height * $scale);
$newImage = imagecreatetruecolor($newImageWidth,$newImageHeight);
$ext = strtolower(substr(basename($image), strrpos(basename($image), ".") + 1));
$source = "";
if($ext == "png"){
$source = imagecreatefrompng($image);
}elseif($ext == "jpg" || $ext == "jpeg"){
$source = imagecreatefromjpeg($image);
}elseif($ext == "gif"){
$source = imagecreatefromgif($image);
}
imagecopyresampled($newImage,$source,0,0,$start_width,$start_height,$newImageWidth,$newImageHeight,$width,$height);
imagejpeg($newImage,$thumb_image_name,90);
chmod($thumb_image_name, 0777);
return $thumb_image_name;
}
function cropImage($thumb_width, $x1, $y1, $x2, $y2, $w, $h, $thumbLocation, $imageLocation){
$scale = $thumb_width/$w;
$cropped = $this->resizeThumbnailImage(WWW_ROOT.str_replace("/", DS,$thumbLocation),WWW_ROOT.str_replace("/", DS,$imageLocation),$w,$h,$x1,$y1,$scale);
return $cropped;
}
}
?>
Then we must create a new helper called cropimage.php (you must create this file in yourapp/views/helpers/ )
Helper Class:
Download code
<?php
class CropimageHelper extends Helper {
var $helpers = array('Html', 'Javascript', 'Form');
function createJavaScript($imgW, $imgH, $thumbW, $thumbH) {
return $this->output("<script type=\"text/javascript\">
function preview(img, selection) {
var scaleX = $thumbW / selection.width;
var scaleY = $thumbW / selection.height;
$('#thumbnail + div > img').css({
width: Math.round(scaleX * $imgW) + 'px',
height: Math.round(scaleY * $imgH) + 'px',
marginLeft: '-' + Math.round(scaleX * selection.x1) + 'px',
marginTop: '-' + Math.round(scaleY * selection.y1) + 'px'
});
$('#x1').val(selection.x1);
$('#y1').val(selection.y1);
$('#x2').val(selection.x2);
$('#y2').val(selection.y2);
$('#w').val(selection.width);
$('#h').val(selection.height);
}
$(document).ready(function () {
$('#save_thumb').click(function() {
var x1 = $('#x1').val();
var y1 = $('#y1').val();
var x2 = $('#x2').val();
var y2 = $('#y2').val();
var w = $('#w').val();
var h = $('#h').val();
if(x1==\"\" || y1==\"\" || x2==\"\" || y2==\"\"|| w==\"\" || h==\"\"){
alert('Please choose a area to crop...');
return false;
}else{
return true;
}
});
});
$(window).load(function () {
$('#thumbnail').imgAreaSelect({ aspectRatio: '1:1', onSelectChange: preview });
});
</script>");
}
function createForm($imagePath, $tH, $tW){
$x1 = $this->Form->hidden('x1', array("value" => "", "id"=>"x1"));
$y1 = $this->Form->hidden('y1', array("value" => "", "id"=>"y1"));
$x2 = $this->Form->hidden('x2', array("value" => "", "id"=>"x2",));
$y2 = $this->Form->hidden('y2', array("value" => "", "id"=>"y2"));
$w = $this->Form->hidden('w', array("value" => "", "id"=>"w"));
$h = $this->Form->hidden('h', array("value" => "", "id"=>"h"));
$imgP = $this->Form->hidden('imagePath', array("value" => $imagePath));
return $this->output("<img src=\"$imagePath\" style=\"float: left; margin-right: 10px;\" id=\"thumbnail\" alt=\"Create Thumbnail\" />
<div style=\"position:relative; overflow:hidden; width:151px; height:151px;\">
<img src=\"$imagePath\" style=\"position: relative;\" alt=\"Thumbnail Preview\" />
</div>
<br style=\"clear:both;\"/>$x1 $y1 $x2 $y2 $w $h $imgP");
}
}
?>
Thats it, now i will tell you something about the
Usage
Ok, now you must add the component and the helper to your controller where you want to use the cropload ( :) )
Download code
var $helpers = array(..., 'Cropimage')
var $components = array(..., 'JqImgcrop');
Now you have to create a form where you can select a image.
I will give you an example:
Download code
<?php echo $form->create('YourModel', array('action' => 'createimage_step2', "enctype" => "multipart/form-data"));?>
<?php
echo $form->input('name');
echo $form->input('image',array("type" => "file"));
echo $form->end('Upload');
?>
Now, in the createimage_step2 function you have to add the upload function of our component:
Download code
$uploaded = $this->JqImgcrop->uploadImage($this->data['YourModel']['image'], '/img/upload/', 'prefix_');
and then push it to the view:
Download code
$this->set('uploaded',$uploaded);
This is what it looks in my controller:
Download code
function createimage_step2(){
if (!empty($this->data)) {
$uploaded = $this->JqImgcrop->uploadImage($this->data['YourModel']['image'], '/img/upload/', 'prefix_');
$this->set('uploaded',$uploaded);
}
Now you have to add in your view ( in my case createimage_step2.ctp ) at the top the 2 Javascript libraries:
Download code
<?php
if(isset($javascript)):
echo $javascript->link('jquery-1.2.6.min.js');
echo $javascript->link('jquery.imgareaselect-0.4.2.min.js');
endif;
?>
Then you have to create a new form with the cropimage helper using:
Download code
echo $cropimage->createForm($uploaded["imagePath"], $width, $height);
The 2 width and height parameters specify the size of the thumbnail which will be created.You have to close the form with a form->submit with the id "save_thumb" Download code
echo $form->submit('Done', array("id"=>"save_thumb"));
In my case it looks like this:
Download code
<?php
echo $form->create('YourModel', array('action' => 'createimage_step3',"enctype" => "multipart/form-data"));
echo $form->input('id');
echo $form->hidden('name');
echo $cropimage->createForm($uploaded["imagePath"], 151, 151);
echo $form->submit('Done', array("id"=>"save_thumb"));
echo $form->end();?>
Final Step
Now, in the createimage_step3 function in your controller we crop and save the image
Download code
$this->JqImgcrop->cropImage(151, $this->data['YourModel']['x1'], $this->data['YourModel']['y1'], $this->data['YourModel']['x2'], $this->data['YourModel']['y2'], $this->data['YourModel']['w'], $this->data['YourModel']['h'], $this->data['YourModel']['imagePath'], $this->data['YourModel']['imagePath'])
The function is using this pararmeters:
Download code
$thumb_width, $x1, $y1, $x2, $y2, $w, $h, $thumbLocation, $imageLocation
$thumb_width is the width of your thumbnail, $x1, $y1, $x2, $y2, $w and $h are including the crop parameters, $thumbLocation the location where you want to save your thumb, and $imageLocation the location of the sourceimage.This function returns the filename of the created thumbnail.
Ok, that's it.
Big thanks to http://www.webmotionuk.co.uk for your great article!
Comments
Comment
1 Small corrections and adjustments
I tryed it and managed to get it work for windows, running Cake 1.2 RC1 on XAMPP PHP 5.2.0
Corrections:
Under Usage:
should beecho $form->input('image',"type" => "file");
echo $form->input('image',array("type" => "file"));
To make it work for windows I needed to change the component
if((!empty($uploadedInfo)) && ($uploadedInfo["error"] == 0)) {
return false;
}
into
if(empty($uploadedInfo)) {
return false;
}
or remove it, as Error allways showed up 0, even on sucess.
Further I removed the two
chmod ($uploadTarget , 0777);
and
chmod($image, 0777);
lines.
My createimage_step2.ctp view needed
echo $cropimage->createJavaScript($uploaded['imageWidth'],$uploaded['imageHeight'],151,151);
to make the script run.
And as I am not running only this app, the image path showed up wrong. So I rewrote the createForm() in the cropimage.php helper, using the html helper to create the images with the correct pats.
function createForm($imagePath, $tH, $tW){
$x1 = $this->Form->hidden('x1', array("value" => "", "id"=>"x1"));
$y1 = $this->Form->hidden('y1', array("value" => "", "id"=>"y1"));
$x2 = $this->Form->hidden('x2', array("value" => "", "id"=>"x2",));
$y2 = $this->Form->hidden('y2', array("value" => "", "id"=>"y2"));
$w = $this->Form->hidden('w', array("value" => "", "id"=>"w"));
$h = $this->Form->hidden('h', array("value" => "", "id"=>"h"));
$imgP = $this->Form->hidden('imagePath', array("value" => $imagePath));
$imgTum = $this->Html->image($imagePath, array('style'=>'float: left; margin-right: 10px;', 'id'=>'thumbnail', 'alt'=>'Create Thumbnail'));
$imgTumPrev = $this->Html->image($imagePath, array('style'=>'position: relative;', 'id'=>'thumbnail', 'alt'=>'Thumbnail Preview'));
return $this->output("$imgTum
<div style=\"position:relative; overflow:hidden; width:151px; height:151px;\">
$imgTumPrev
</div>
<br style=\"clear:both;\"/>$x1 $y1 $x2 $y2 $w $h $imgP");
}
Comment
2 really nice thing but not quite working
i even got it to work - partly - and only with the correctios of Eskil
the main problem is this crap about these DS-Seperators
once it works in createimage_part2, but then theres one Slash to much for _part3, this is on localhost (windows xp)
then i upload it on my webspace, now the slahes are the other way arround and still everything is just really messy and nothing actually works.
what can i do about it?
isn't there a nice function or something to be able to work with http paths like "http://localhost/cake/img/upload/pic.jpg"?
or even better with relative ones like "/cake/img/upload/pic.jpg"?
i used to do that with my upload scripts once..
this worked on localhost as well as in the www
in this case this whole thing about this paths "F:\xampp\htdocs\cake\app\webroot\/img/temp_pic.jpg" etc would't even occur.. or?
i mean, this relative and http paths always use this one forward slash: /
well, i tried about all kinds of things, i'm so tired of it.
i hope somebody can help
i already startet to put some constants in my bootstrap.php to get this thing fixed:
define('HTTP_HOST',$_SERVER['HTTP_HOST']); // e.g. localhost
define('HTTP_BASE', 'http://'.HTTP_HOST.'/'); // e.g. http://localhost/
define ('PATH_REL', '/home/cake/'); // e.g. /home/cake/
define ('PATH_HOME', 'http://'.HTTP_HOST.PATH_REL); // e.g. http://localhost/home/cake/
but this can't be the intention of our Cake-Programmers to workaround it, can it?
Comment
3 Hmm
Thanks to Eskil and Mark.
Comment
4 Very cool script
just tested after some tweaking (thank you Eskil) it works on my Mac.
Note that I modified the cropImage return's to:
//return $cropped;return $imageLocation;
In this way you can display directly the cropped image in the final page:
<?phpecho $html->image($uploaded);
?>
Thanks a lot!