Image upload for preview and jcrop

Hi,

Im trying to create a registration form in which users can upload an image and crop It with yii-jcrop extension. How could I upload user’s image using ajax and then allow yii-jcrop to work with It before form submission?

Here is my code ($imageUrl should get uploaded image path+filename):


<div class="row">

	<?php echo $form->labelEx($model,'image'); ?>

	<?php echo $form->fileField($model,'image'); ?>

	<?php echo $form->error($model,'image'); ?>

	<?php


	$imageUrl = 'test_avatar.gif';

	echo $form->hiddenField($model,'cropID');

	echo $form->hiddenField($model,'cropX', array('value' => '0'));

	echo $form->hiddenField($model,'cropY', array('value' => '0'));

	echo $form->hiddenField($model,'cropW', array('value' => '100'));

	echo $form->hiddenField($model,'cropH', array('value' => '100'));

	

	$previewWidth = 100; $previewHeight = 100;

	$this->widget('ext.yii-jcrop.jCropWidget',array(

		'imageUrl'=>$imageUrl,

		'formElementX'=>'Users_cropX',

		'formElementY'=>'Users_cropY',

		'formElementWidth'=>'Users_cropW',

		'formElementHeight'=>'Users_cropH',

		'previewId'=>'avatar-preview', //optional preview image ID, see preview div below

		'previewWidth'=>$previewWidth,

		'previewHeight'=>$previewHeight,

		'jCropOptions'=>array(

			'aspectRatio'=>1, 

			'boxWidth'=>400,

			'boxHeight'=>400,

			'setSelect'=>array(0, 0, 100, 100),

		),

	));


?>

</div>

Thank you in advance

I managed to use EAjaxUpload Extension but i’d need help on creating yii-jcrop for uploaded image.

How could I create a modal dialog box just after uploading (ajax) the image? Just below code but after uploading


$this->beginWidget('zii.widgets.jui.CJuiDialog'

        , array('options'=>array(

            'title'=>'Crop'

            , 'modal'=>true

			, 'width'=>728

			, 'height'=>600

            , 'buttons'=>array('OK'=>'js:function(){$(this).dialog("close")}')

            ))

		);

		$previewWidth = 100; $previewHeight = 100;

		$this->widget('ext.yii-jcrop.jCropWidget',array(

			'imageUrl'=>$imageUrl,

			'formElementX'=>'Users_cropX',

			'formElementY'=>'Users_cropY',

			'formElementWidth'=>'Users_cropW',

			'formElementHeight'=>'Users_cropH',

			'previewId'=>'avatar-preview', //optional preview image ID, see preview div below

			'previewWidth'=>$previewWidth,

			'previewHeight'=>$previewHeight,

			'jCropOptions'=>array(

				'aspectRatio'=>1, 

				'boxWidth'=>400,

				'boxHeight'=>400,

				'setSelect'=>array(0, 0, 100, 100),

			),

		));

Can you post the code used to upload the image?

Sure, here you are:

Form code:




<div class="row">

	<?php echo $form->labelEx($model,'image'); ?>

	<?php echo $form->hiddenField($model,'image',array('maxlength'=>100)); ?>

	<?php echo $form->error($model,'image'); ?>


	<?php


	$this->widget('ext.EAjaxUpload.EAjaxUpload',

	array(

	'id'=>'uploadFile',

	'config'=>array(

	       'action'=>Yii::app()->baseUrl.'/index.php/users/upload',

	       'allowedExtensions'=>array("jpg", "jpeg", "gif", "png"),//array("jpg","jpeg","gif","exe","mov" and etc...

	       'sizeLimit'=>10*1024*1024,// maximum file size in bytes

	       'minSizeLimit'=>1024,// minimum file size in bytes

	      )

	));

	?>



Controller code (note that ive commented filesize function call because it returns an error for me):




public function actionUpload()

{

	Yii::import("ext.EAjaxUpload.qqFileUploader");

 

	//$folder=Yii::getPathOfAlias('application.uploads');// folder for uploaded files

	$folder='upload/';

			

	$allowedExtensions = array("jpg", "jpeg", "gif", "png");//array("jpg","jpeg","gif","exe","mov" and etc...

	$sizeLimit = 10 * 1024 * 1024;// maximum file size in bytes

	$uploader = new qqFileUploader($allowedExtensions, $sizeLimit);

	$result = $uploader->handleUpload($folder);

	$result=htmlspecialchars(json_encode($result), ENT_NOQUOTES);


	//$fileSize=filesize($folder.$result['filename']); //GETTING FILE SIZE

	$fileName=$result['filename'];//GETTING FILE NAME

 

	echo $result;// it's array


}



There’s a bug in this code, but I think you want something like this

Actions




	public function actionFormUpload()

	{

		$this->render('upload');

	}


	public function actionCropImg()

	{

    	Yii::app()->clientScript->scriptMap=array(

		   (YII_DEBUG ?  'jquery.js':'jquery.min.js')=>false,

		);

		$imageUrl = Yii::app()->request->baseUrl . '/upload/'. $_GET['fileName'];

		$this->renderPartial('cropImg', array('imageUrl'=>$imageUrl), false, true);

	}


	public function actionUpload()

	{

    	Yii::import("ext.EAjaxUpload.qqFileUploader");

 

    	$folder='upload/';// folder for uploaded files

    	$allowedExtensions = array("jpg");//array("jpg","jpeg","gif","exe","mov" and etc...

    	$sizeLimit = 10 * 1024 * 1024;// maximum file size in bytes

    	$uploader = new qqFileUploader($allowedExtensions, $sizeLimit);

    	$result = $uploader->handleUpload($folder);

	

    	$fileSize=filesize($folder.$result['filename']);//GETTING FILE SIZE

    	$fileName=$result['filename'];//GETTING FILE NAME

		$result=htmlspecialchars(json_encode($result), ENT_NOQUOTES);

    	echo $result;// it's array

	}



View upload.php




<?php 

$this->widget('ext.EAjaxUpload.EAjaxUpload',

array(

    	'id'=>'uploadFile',

    	'config'=>array(

   			'action'=> $this->createUrl('upload'),

   			'allowedExtensions'=>array("jpg"),//array("jpg","jpeg","gif","exe","mov" and etc...

   			'sizeLimit'=>10*1024*1024,// maximum file size in bytes

   			'minSizeLimit'=>10,//*1024*1024,// minimum file size in bytes

   			'onComplete'=>"js:function(id, fileName, responseJSON){ 

								$('#cropImg').load('". $this->createUrl('cropImg') ."/fileName/'+fileName);

								$('#cropDialog').dialog('open');

							}",

   			//'messages'=>array(

   			//              	'typeError'=>"{file} has invalid extension. Only {extensions} are allowed.",

   			//              	'sizeError'=>"{file} is too large, maximum file size is {sizeLimit}.",

   			//              	'minSizeError'=>"{file} is too small, minimum file size is {minSizeLimit}.",

   			//              	'emptyError'=>"{file} is empty, please select files again without it.",

   			//              	'onLeave'=>"The files are being uploaded, if you leave now the upload will be cancelled."

   			//     			),

   			'showMessage'=>"js:function(message){ alert(message); }"

          	)

));

?>


<?php 

$this->beginWidget('zii.widgets.jui.CJuiDialog',

			array(

				'id'=>'cropDialog', 

				'options'=>

					array(

						'title'=>'Crop', 

						'modal'=>true, 

						'width'=>728,

						'height'=>600,

						'buttons'=>array('OK'=>'js:function(){$(this).dialog("close")}'),

						'autoOpen'=>false,

	    			)

			));


	echo '<div id="cropImg"></div>';


$this->endWidget('zii.widgets.jui.CJuiDialog');

?>



View cropImg.php




<?php echo CHtml::beginForm(null, 'POST')?>

	<?php //$form in this example is of type AvatarForm, containing variables for the crop area's x, y, width and height, hence the corresponding widget form element parameters ?>

	<?php echo CHtml::hiddenField('cropID', 'cropID');?>

	<?php echo CHtml::hiddenField('cropX', 'cropX', array('value' => '0'));?>

	<?php echo CHtml::hiddenField('cropY', 'cropY', array('value' => '0'));?>

	<?php echo CHtml::hiddenField('cropW', 'cropW', array('value' => '100'));?>

	<?php echo CHtml::hiddenField('cropH', 'cropH', array('value' => '100'));?>

	<?php $previewWidth = 100; $previewHeight = 100;?>

	<?php $this->widget('ext.yii-jcrop.jCropWidget',array(

    	'imageUrl'=>$imageUrl,

    	'formElementX'=>'AvatarForm_cropX',

    	'formElementY'=>'AvatarForm_cropY',

    	'formElementWidth'=>'AvatarForm_cropW',

    	'formElementHeight'=>'AvatarForm_cropH',

    	'previewId'=>'avatar-preview', //optional preview image ID, see preview div below

    	'previewWidth'=>$previewWidth,

    	'previewHeight'=>$previewHeight,

    	'jCropOptions'=>array(

        	'aspectRatio'=>1, 

        	'boxWidth'=>400,

        	'boxHeight'=>400,

        	'setSelect'=>array(0, 0, 100, 100),

    	),

	)

	);

	?>

 	<?php echo CHtml::submitButton('Crop Avatar'); ?>

<?php echo CHtml::endForm()?>



Thank you so much!

Im testing it right now and really works for me. I’ll post modifications because i need it to be sent from a single post request.

Again, thank you

Here is my approach:

Controller:




	public function actionFormUpload()

	{

		$this->render('upload');

	}


	public function actionCropImg()

	{

		Yii::app()->clientScript->scriptMap=array(

			(YII_DEBUG ?  'jquery.js':'jquery.min.js')=>false,

		);

		$imageUrl = Yii::app()->request->baseUrl . '/images/users/'. $_GET['fileName'];

		$this->renderPartial('cropImg', array('imageUrl'=>$imageUrl), false, true);

	}


	public function actionUpload()

	{

		Yii::import("ext.EAjaxUpload.qqFileUploader");


		$folder='images/users/';// folder for uploaded files

		$allowedExtensions = array("jpg", "jpeg", "gif", "png");//array("jpg","jpeg","gif","exe","mov" and etc...

		$sizeLimit = 1 * 1024 * 1024;// maximum file size in bytes

		$uploader = new qqFileUploader($allowedExtensions, $sizeLimit);

		$result = $uploader->handleUpload($folder);


		$fileSize=filesize($folder.$result['filename']);//GETTING FILE SIZE

		$fileName=$result['filename'];//GETTING FILE NAME


		$result=htmlspecialchars(json_encode($result), ENT_NOQUOTES);

		echo $result;// it's array

	}

	



Model: (seems that beforesave doesnt work :??)





	// before saving we'll crop the image

	protected function beforeSave()

	{

		if ($this->isNewRecord) {

			$this->passwordHash = sha1($this->password);

		}

		

		$path = "/home/www/images/users/";

		$filename = $this->image;

		$filetype = $this->imageExt;


		$this->image = $this->email.$filetype;


		//cropping image

		$xCoord = $this->cropX; /* these two fields are the (x,y) coordinates */

		$yCoord = $this->cropY; /*  of the top left corner of our new image  */

		

		$width = $this->cropW; // width of the cropped area

		$height = $this->cropH; // height of the cropped area


		if ($filetype == '.jpeg' || $filetype == '.jpg') {

			$img = imagecreatefromjpeg($path.$filename);

		} else if ($filetype == '.gif') {

			$img = imagecreatefromgif($path.$filename);

		}  else if ($filetype == '.png') {

			$img = imagecreatefrompng($path.$filename);

		}

			

		//create a new PHP image object to hold the cropped image, and crop the image

		$newImage = imagecreatetruecolor($width, $height);

		imagecopyresampled($newImage, $img, 0, 0, $xCoord, $yCoord, $width, $height, $width, $height);

		//convert the PHP image object to a .png file

		imagepng($newImage, $path.$filename, 0);

		//cleanup

		imagedestroy($img);

		imagedestroy($newImage);


		// renaming old image name to user's email

		rename($path.$filename, $path.$this->image);


		return parent::beforeSave(); // don't forget this line!


	}



View:




<?php $previewWidth = 100; $previewHeight = 100;?>

<?php $this->widget('ext.yii-jcrop.jCropWidget',array(

	'imageUrl'=>$imageUrl,

	'formElementX'=>'Users_cropX',

	'formElementY'=>'Users_cropY',

	'formElementWidth'=>'Users_cropW',

	'formElementHeight'=>'Users_cropH',

	'previewId'=>'avatar-preview', //optional preview image ID, see preview div below

	'previewWidth'=>$previewWidth,

	'previewHeight'=>$previewHeight,

	'jCropOptions'=>array(

		'aspectRatio'=>1, 

		'minSize'=>array(100, 100),

		'maxSize'=>array(100, 100),

		'boxWidth'=>400,

		'boxHeight'=>400,

		'setSelect'=>array(0, 0, 100, 100),

	),

	)

);

?>

<div id="avatar-thumb" style="position:relative; overflow:hidden; width:<?=$previewWidth?>px; height:<?=$previewHeight?>px; margin-top: 10px; margin-bottom: 10px;">

	<img id="avatar-preview" src="<?=$imageUrl?>" style="width: 0px; height: 0px; margin-left: 0px; margin-top: 0px;">

</div>



Form:




	<div class="row">

		<?php echo $form->labelEx($model,'image'); ?>

		<?php echo $form->hiddenField($model,'image',array('maxlength'=>100)); ?>

		<?php echo $form->hiddenField($model,'imageExt',array('maxlength'=>100)); ?>

		<?php echo $form->error($model,'image'); 


		echo $form->hiddenField($model,'cropID');

		echo $form->hiddenField($model,'cropX', array('value' => '0'));

		echo $form->hiddenField($model,'cropY', array('value' => '0'));

		echo $form->hiddenField($model,'cropW', array('value' => '100'));

		echo $form->hiddenField($model,'cropH', array('value' => '100'));


		?>


		<?php

        

		$this->widget('ext.EAjaxUpload.EAjaxUpload',

		array(

			'id'=>'uploadFile',

			'config'=>array(

				'action'=> $this->createUrl('upload'),

				'allowedExtensions'=> array("jpg", "jpeg", "gif", "png"),//array("jpg","jpeg","gif","exe","mov" and etc...

				'sizeLimit'=>500*1024,// maximum file size in bytes

				'minSizeLimit'=>10,//*1024*1024,// minimum file size in bytes

				'onComplete'=>"js:function(id, fileName, responseJSON){ 

					$('#uploadFile').hide();

					if (responseJSON.success) {

						$('#cropImg').load('". $this->createUrl('cropImg') ."/fileName/'+fileName);

						$('#cropDialog').dialog('open');

						$('#Users_image').val(responseJSON.filename);

						$('#Users_imageExt').val((responseJSON.filename.substring(responseJSON.filename.lastIndexOf('.'))).toLowerCase());

						$('#uploadFile').show();

						$('.qq-upload-button').css('display', 'none');

					} else {

						$('#uploadFile').html('<p  width=\"160\">' + responseJSON.error +'</p>');

					}

				}",

				//'messages'=>array(

				//                      'typeError'=>"{file} has invalid extension. Only {extensions} are allowed.",

				//                      'sizeError'=>"{file} is too large, maximum file size is {sizeLimit}.",

				//                      'minSizeError'=>"{file} is too small, minimum file size is {minSizeLimit}.",

				//                      'emptyError'=>"{file} is empty, please select files again without it.",

				//                      'onLeave'=>"The files are being uploaded, if you leave now the upload will be cancelled."

				//                      ),

				'showMessage'=>"js:function(message){ alert(message); }"

			)

		));

		?>


		<?php 

		$this->beginWidget('zii.widgets.jui.CJuiDialog',

			array(

				'id'=>'cropDialog', 

				'options'=> array(

					'title'=>'Crop', 

					'modal'=>true, 

					'width'=>728,

					'height'=>600,

					'buttons'=>array('CROP'=>'js:function(){$(this).dialog("close")}'),

					'autoOpen'=>false,

				)

			));


		echo '<div id="cropImg"></div>';


		$this->endWidget('zii.widgets.jui.CJuiDialog');

		?>


	</div>



the function beforeSave() shouldn’t be in model?

Yes, it is. But seems that im missing something because it doesnt get cropx, cropy etc.

Try change this in beforeSave()




            	if ($filetype == '.jpeg' || $filetype == '.jpg') {

                    	$img = imagecreatefromjpeg($path.$filename.$filetype);

            	} else if ($filetype == '.gif') {

                    	$img = imagecreatefromgif($path.$filename.$filetype);

            	}  else if ($filetype == '.png') {

                    	$img = imagecreatefrompng($path.$filename.$filetype);

            	}



Your code is right one but seems that the thing is that cropX, xropY, cropW and cropH are empty. Ive entered this:

if(!empty($this->image) && !empty($this->cropX) && !empty($this->cropY) && !empty($this->cropW) && !empty($this->cropH))

And image gets value but the rest are empty so It does not execute crop functions

Again, thank you so much

Check if they are set on $_POST


CVarDumper::dump($_POST, 10, true); exit();

Then try to set




$model->cropX = $_POST['Users']['cropX']; /* these two fields are the (x,y) coordinates */

$model->cropY = $_POST['Users']['cropY']; /*  of the top left corner of our new image  */

$model->cropW = $_POST['Users']['cropW']; // width of the cropped area

$model->cropH = $_POST['Users']['cropH'];



Thank you so much EvandroSwk! It worked :)

Im now trying to figure out how to get image original height&width from the controller in actionUpload to modify hidden fields

echo $form->hiddenField($model,‘cropOrigW’, array(‘value’ => ‘’));

echo $form->hiddenField($model,‘cropOrigH’, array(‘value’ => ‘’));

in my form

Again, thank you

Use the function


array getimagesize ( string $filename [, array &$imageinfo] ) 

Yes, that-s what im trying but i cant manage to update forms hidden fields from the controller with image attributes:




	public function actionUpload()

	{

		Yii::import("ext.EAjaxUpload.qqFileUploader");


		$folder='images/users/';// folder for uploaded files

		$allowedExtensions = array("jpg", "jpeg", "gif", "png");//array("jpg","jpeg","gif","exe","mov" and etc...

		$sizeLimit = 1 * 1024 * 1024;// maximum file size in bytes

		$uploader = new qqFileUploader($allowedExtensions, $sizeLimit);

		$result = $uploader->handleUpload($folder);


		$fileSize=filesize($folder.$result['filename']);//GETTING FILE SIZE

		$fileName=$result['filename'];//GETTING FILE NAME

		$fileDim=getimagesize($folder.$result['filename']);

		

                $fileWidth=$fileDim[0];

		$fileHeight=$fileDim[1];


		$result=htmlspecialchars(json_encode($result), ENT_NOQUOTES);

		echo $result;// it's array

	}




Uh forget that. Its better to get dim when cropping and not from the controller.

Thank you again

Add this to actionUpload




$fileDim=getimagesize($folder.$result['filename']);

$result['width'] = $fileDim[0];

$result['height'] = $fileDim[1];



then width and height will be on the var responseJSON

Can you please paste complete/final code here? I also want to do same.

I tried this code. I can upload image but cannot crop. :(

It works correctly, but when the file name includes special (hungarian characters) letters, I get a wrong filename without any extension!

That means I got an 404 Error

THX