')
+ .append(degree)
+ .append($('
').text(fm.i18n('degree')))
+ )
+ .append($(uibuttonset).append(uideg270).append($(uiseparator)).append(uideg90))
+ )
+ .append(uidegslider)
+ );
+
dialog.append(uitype);
control.append($(row))
.append(uiresize)
.append(uicrop.hide())
+ .append(uirotate.hide())
.find('input,select').attr('disabled', 'disabled');
rhandle.append('
')
@@ -326,7 +536,8 @@ elFinder.prototype.commands.resize = function() {
preview.append(spinner).append(rhandle.hide()).append(img.hide());
- rhandlec.append('
')
+ rhandlec.css('position', 'absolute')
+ .append('
')
.append('
')
.append('
')
.append('
')
@@ -334,8 +545,12 @@ elFinder.prototype.commands.resize = function() {
.append('
')
.append('
')
- preview.append(rhandlec.hide()).append(imgc.hide());
-
+ preview.append(basec.hide().append(imgc).append(rhandlec.append(coverc)));
+
+ preview.append(imgr.hide());
+
+ preview.css('overflow', 'hidden');
+
dialog.append(preview).append(control);
buttons[fm.i18n('btnCancel')] = function() { dialog.elfinderdialog('close'); };
@@ -350,18 +565,38 @@ elFinder.prototype.commands.resize = function() {
open : function() { preview.zIndex(1+$(this).parent().zIndex()); }
}).attr('id', id);
+ // for IE < 9 dialog mising at open second+ time.
+ if ($.browser.msie && parseInt($.browser.version) < 9) {
+ $('.elfinder-dialog').css('filter', '');
+ }
+
reset.css('left', width.position().left + width.width() + 12);
+ coverc.css({ 'opacity': 0.2, 'background-color': '#fff', 'position': 'absolute'}),
+ rhandlec.css('cursor', 'move');
+ rhandlec.find('.elfinder-resize-handle-point').css({
+ 'background-color' : '#fff',
+ 'opacity': 0.5,
+ 'border-color':'#000'
+ });
+
+ imgr.css('cursor', 'pointer');
+
+ uitype.buttonset();
+
pwidth = preview.width() - (rhandle.outerWidth() - rhandle.width());
pheight = preview.height() - (rhandle.outerHeight() - rhandle.height());
-
+
img.attr('src', src + (src.indexOf('?') === -1 ? '?' : '&')+'_='+Math.random());
imgc.attr('src', img.attr('src'));
+ imgr.attr('src', img.attr('src'));
+
},
id, dialog
;
+
if (!files.length || files[0].mime.indexOf('image/') === -1) {
return dfrd.reject();
}
@@ -374,9 +609,165 @@ elFinder.prototype.commands.resize = function() {
return dfrd.resolve();
}
- open(files[0], id)
+ open(files[0], id);
return dfrd;
}
-}
+};
+
+(function ($) {
+
+ var findProperty = function (styleObject, styleArgs) {
+ var i = 0 ;
+ for( i in styleArgs) {
+ if (typeof styleObject[styleArgs[i]] != 'undefined')
+ return styleArgs[i];
+ }
+ styleObject[styleArgs[i]] = '';
+ return styleArgs[i];
+ };
+
+ $.cssHooks.rotate = {
+ get: function(elem, computed, extra) {
+ return $(elem).rotate();
+ },
+ set: function(elem, value) {
+ $(elem).rotate(value);
+ return value;
+ }
+ };
+ $.cssHooks.transform = {
+ get: function(elem, computed, extra) {
+ var name = findProperty( elem.style ,
+ ['WebkitTransform', 'MozTransform', 'OTransform' , 'msTransform' , 'transform'] );
+ return elem.style[name];
+ },
+ set: function(elem, value) {
+ var name = findProperty( elem.style ,
+ ['WebkitTransform', 'MozTransform', 'OTransform' , 'msTransform' , 'transform'] );
+ elem.style[name] = value;
+ return value;
+ }
+ };
+
+ $.fn.rotate = function(val) {
+ if (typeof val == 'undefined') {
+ if ($.browser.opera) {
+ var r = this.css('transform').match(/rotate\((.*?)\)/);
+ return ( r && r[1])?
+ Math.round(parseFloat(r[1]) * 180 / Math.PI) : 0;
+ } else {
+ var r = this.css('transform').match(/rotate\((.*?)\)/);
+ return ( r && r[1])? parseInt(r[1]) : 0;
+ }
+ }
+ this.css('transform',
+ this.css('transform').replace(/none|rotate\(.*?\)/, '') + 'rotate(' + parseInt(val) + 'deg)');
+ return this;
+ };
+
+ $.fx.step.rotate = function(fx) {
+ if ( fx.state == 0 ) {
+ fx.start = $(fx.elem).rotate();
+ fx.now = fx.start;
+ }
+ $(fx.elem).rotate(fx.now);
+ };
+
+ if ($.browser.msie && parseInt($.browser.version) < 9) {
+ var GetAbsoluteXY = function(element) {
+ var pnode = element;
+ var x = pnode.offsetLeft;
+ var y = pnode.offsetTop;
+
+ while ( pnode.offsetParent ) {
+ pnode = pnode.offsetParent;
+ if (pnode != document.body && pnode.currentStyle['position'] != 'static') {
+ break;
+ }
+ if (pnode != document.body && pnode != document.documentElement) {
+ x -= pnode.scrollLeft;
+ y -= pnode.scrollTop;
+ }
+ x += pnode.offsetLeft;
+ y += pnode.offsetTop;
+ }
+
+ return { x: x, y: y };
+ };
+
+ var StaticToAbsolute = function (element) {
+ if ( element.currentStyle['position'] != 'static') {
+ return ;
+ }
+
+ var xy = GetAbsoluteXY(element);
+ element.style.position = 'absolute' ;
+ element.style.left = xy.x + 'px';
+ element.style.top = xy.y + 'px';
+ };
+
+ var IETransform = function(element,transform){
+
+ var r;
+ var m11 = 1;
+ var m12 = 1;
+ var m21 = 1;
+ var m22 = 1;
+
+ if (typeof element.style['msTransform'] != 'undefined'){
+ return true;
+ }
+
+ StaticToAbsolute(element);
+
+ r = transform.match(/rotate\((.*?)\)/);
+ var rotate = ( r && r[1]) ? parseInt(r[1]) : 0;
+
+ rotate = rotate % 360;
+ if (rotate < 0) rotate = 360 + rotate;
+
+ var radian= rotate * Math.PI / 180;
+ var cosX =Math.cos(radian);
+ var sinY =Math.sin(radian);
+
+ m11 *= cosX;
+ m12 *= -sinY;
+ m21 *= sinY;
+ m22 *= cosX;
+
+ element.style.filter = (element.style.filter || '').replace(/progid:DXImageTransform\.Microsoft\.Matrix\([^)]*\)/, "" ) +
+ ("progid:DXImageTransform.Microsoft.Matrix(" +
+ "M11=" + m11 +
+ ",M12=" + m12 +
+ ",M21=" + m21 +
+ ",M22=" + m22 +
+ ",FilterType='bilinear',sizingMethod='auto expand')")
+ ;
+
+ var ow = parseInt(element.style.width || element.width || 0 );
+ var oh = parseInt(element.style.height || element.height || 0 );
+
+ var radian = rotate * Math.PI / 180;
+ var absCosX =Math.abs(Math.cos(radian));
+ var absSinY =Math.abs(Math.sin(radian));
+
+ var dx = (ow - (ow * absCosX + oh * absSinY)) / 2;
+ var dy = (oh - (ow * absSinY + oh * absCosX)) / 2;
+
+ element.style.marginLeft = Math.floor(dx) + "px";
+ element.style.marginTop = Math.floor(dy) + "px";
+
+ return(true);
+ };
+
+ var transform_set = $.cssHooks.transform.set;
+ $.cssHooks.transform.set = function(elem, value) {
+ transform_set.apply(this, [elem, value] );
+ IETransform(elem,value);
+ return value;
+ };
+ }
+
+})(jQuery);
diff --git a/js/i18n/elfinder.LANG.js b/js/i18n/elfinder.LANG.js
index 1c9a882d9..8356e8ac7 100644
--- a/js/i18n/elfinder.LANG.js
+++ b/js/i18n/elfinder.LANG.js
@@ -233,7 +233,10 @@ if (elFinder && elFinder.prototype && typeof(elFinder.prototype.i18) == 'object'
'mode' : 'Mode',
'resize' : 'Resize',
'crop' : 'Crop',
-
+ 'rotate' : 'Rotate',
+ 'rotate-cw' : 'Rotate 90 degrees CW',
+ 'rotate-ccw' : 'Rotate 90 degrees CCW',
+ 'degree' : 'Degree',
/********************************** mimetypes **********************************/
'kindUnknown' : 'Unknown',
diff --git a/js/i18n/elfinder.en.js b/js/i18n/elfinder.en.js
index 9e1fd8f57..66b597625 100644
--- a/js/i18n/elfinder.en.js
+++ b/js/i18n/elfinder.en.js
@@ -1,7 +1,7 @@
/**
* English translation
* @author Troex Nevelin
- * @version 2011-07-10
+ * @version 2012-02-25
*/
if (elFinder && elFinder.prototype && typeof(elFinder.prototype.i18) == 'object') {
elFinder.prototype.i18.en = {
@@ -101,7 +101,7 @@ if (elFinder && elFinder.prototype && typeof(elFinder.prototype.i18) == 'object'
'cmdup' : 'Go to parent directory',
'cmdupload' : 'Upload files',
'cmdview' : 'View',
- 'cmdresize' : 'Resize image',
+ 'cmdresize' : 'Resize & Rotate',
'cmdsort' : 'Sort',
/*********************************** buttons ***********************************/
@@ -226,9 +226,12 @@ if (elFinder && elFinder.prototype && typeof(elFinder.prototype.i18) == 'object'
'scale' : 'Scale',
'width' : 'Width',
'height' : 'Height',
- 'mode' : 'Mode',
- 'resize' : 'Resize',
- 'crop' : 'Crop',
+ 'resize' : 'Resize',
+ 'crop' : 'Crop',
+ 'rotate' : 'Rotate',
+ 'rotate-cw' : 'Rotate 90 degrees CW',
+ 'rotate-ccw' : 'Rotate 90 degrees CCW',
+ 'degree' : '°',
/********************************** mimetypes **********************************/
'kindUnknown' : 'Unknown',
diff --git a/js/i18n/elfinder.jp.js b/js/i18n/elfinder.jp.js
index 2cab79c8a..9d60e3e4d 100644
--- a/js/i18n/elfinder.jp.js
+++ b/js/i18n/elfinder.jp.js
@@ -1,7 +1,7 @@
/**
* Japanese translation
* @author Tomoaki Yoshida
- * @version 2012-02-22
+ * @version 2012-02-25
*/
if (elFinder && elFinder.prototype && typeof(elFinder.prototype.i18) == 'object') {
elFinder.prototype.i18.jp = {
@@ -101,7 +101,7 @@ if (elFinder && elFinder.prototype && typeof(elFinder.prototype.i18) == 'object'
'cmdup' : '親ディレクトリーへ移動',
'cmdupload' : 'ファイルアップロード',
'cmdview' : 'ビュー',
- 'cmdresize' : 'リサイズ',
+ 'cmdresize' : 'リサイズと回転',
'cmdsort' : 'ソート',
/*********************************** buttons ***********************************/
@@ -226,9 +226,12 @@ if (elFinder && elFinder.prototype && typeof(elFinder.prototype.i18) == 'object'
'scale' : '表示縮尺',
'width' : '幅',
'height' : '高さ',
- 'mode' : 'モード',
'resize' : 'リサイズ',
'crop' : '切り抜き',
+ 'rotate' : '回転',
+ 'rotate-cw' : '90度左回転',
+ 'rotate-ccw' : '90度右回転',
+ 'degree' : '度',
/********************************** mimetypes **********************************/
'kindUnknown' : '不明',
diff --git a/js/i18n/elfinder.ru.js b/js/i18n/elfinder.ru.js
index 2aa2677b2..439e0c840 100644
--- a/js/i18n/elfinder.ru.js
+++ b/js/i18n/elfinder.ru.js
@@ -222,7 +222,13 @@ if (elFinder && elFinder.prototype && typeof(elFinder.prototype.i18) == 'object'
'scale' : 'Масштаб',
'width' : 'Ширина',
'height' : 'Высота',
-
+ 'resize' : 'Размер',
+ 'crop' : 'Кадрировать',
+ 'rotate' : 'Поворот',
+ 'rotate-cw' : 'Поворот на 90 градусов по часовой стрелке',
+ 'rotate-ccw' : 'Поворот на 90 градусов против часовой стрелке',
+ 'degree' : '°',
+
/********************************** mimetypes **********************************/
'kindUnknown' : 'Неизвестный',
'kindFolder' : 'Папка',
diff --git a/php/elFinder.class.php b/php/elFinder.class.php
index ab3305093..5b1508505 100644
--- a/php/elFinder.class.php
+++ b/php/elFinder.class.php
@@ -67,7 +67,7 @@ class elFinder {
'search' => array('q' => true, 'mimes' => false),
'info' => array('targets' => true),
'dim' => array('target' => true),
- 'resize' => array('target' => true, 'width' => true, 'height' => true, 'mode' => false, 'x' => false, 'y' => false)
+ 'resize' => array('target' => true, 'width' => true, 'height' => true, 'mode' => false, 'x' => false, 'y' => false, 'degree' => false)
);
/**
@@ -1020,13 +1020,15 @@ class elFinder {
$x = (int)$args['x'];
$y = (int)$args['y'];
$mode = $args['mode'];
+ $bg = null;
+ $degree = (int)$args['degree'];
if (($volume = $this->volume($target)) == false
|| ($file = $volume->file($target)) == false) {
return array('error' => $this->error(self::ERROR_RESIZE, '#'.$target, self::ERROR_FILE_NOT_FOUND));
}
- return ($file = $volume->resize($target, $width, $height, $x, $y, $mode))
+ return ($file = $volume->resize($target, $width, $height, $x, $y, $mode, $bg, $degree))
? array('changed' => array($file))
: array('error' => $this->error(self::ERROR_RESIZE, $volume->path($target), $volume->error()));
}
diff --git a/php/elFinderVolumeDriver.class.php b/php/elFinderVolumeDriver.class.php
index 9d1cfb96f..a1b926ab4 100644
--- a/php/elFinderVolumeDriver.class.php
+++ b/php/elFinderVolumeDriver.class.php
@@ -1624,12 +1624,16 @@ abstract class elFinderVolumeDriver {
* @param string $hash image file
* @param int $width new width
* @param int $height new height
- * @param bool $crop crop image
+ * @param int $x X start poistion for crop
+ * @param int $y Y start poistion for crop
+ * @param string $mode action how to mainpulate image
* @return array|false
* @author Dmitry (dio) Levashov
* @author Alexey Sukhotin
+ * @author nao-pon
+ * @author Troex Nevelin
**/
- public function resize($hash, $width, $height, $x, $y, $mode = 'resize', $bg='') {
+ public function resize($hash, $width, $height, $x, $y, $mode = 'resize', $bg = '', $degree = 0) {
if ($this->commandDisabled('resize')) {
return $this->setError(elFinder::ERROR_PERM_DENIED);
}
@@ -1659,14 +1663,18 @@ abstract class elFinderVolumeDriver {
break;
case 'fitsquare':
- $result = $this->imgSquareFit($path, $width, $height, 'center', 'middle', $bg ? $bg : $this->options['tmbBgColor']);
+ $result = $this->imgSquareFit($path, $width, $height, 'center', 'middle', ($bg ? $bg : $this->options['tmbBgColor']));
break;
-
+
+ case 'rotate':
+ $result = $this->imgRotate($path, $degree, ($bg ? $bg : $this->options['tmbBgColor']));
+ break;
+
default:
$result = $this->imgResize($path, $width, $height, false, true);
- break;
- }
-
+ break;
+ }
+
if ($result) {
if (!empty($file['tmb']) && $file['tmb'] != "1") {
$this->rmTmb($file['tmb']);
@@ -2635,7 +2643,8 @@ abstract class elFinderVolumeDriver {
* @param bool $resizeByBiggerSide resize image based on bigger side if true
* @param string $destformat image destination format
* @return string|false
- * @author Dmitry (dio) Levashov, Alexey Sukhotin
+ * @author Dmitry (dio) Levashov
+ * @author Alexey Sukhotin
**/
protected function imgResize($path, $width, $height, $keepProportions = false, $resizeByBiggerSide = true, $destformat = null) {
if (($s = @getimagesize($path)) == false) {
@@ -2741,7 +2750,8 @@ abstract class elFinderVolumeDriver {
* @param bool $y crop top offset
* @param string $destformat image destination format
* @return string|false
- * @author Dmitry (dio) Levashov, Alexey Sukhotin
+ * @author Dmitry (dio) Levashov
+ * @author Alexey Sukhotin
**/
protected function imgCrop($path, $width, $height, $x, $y, $destformat = null) {
if (($s = @getimagesize($path)) == false) {
@@ -2816,9 +2826,10 @@ abstract class elFinderVolumeDriver {
* @param string $bgcolor square background color in #rrggbb format
* @param string $destformat image destination format
* @return string|false
- * @author Dmitry (dio) Levashov, Alexey Sukhotin
+ * @author Dmitry (dio) Levashov
+ * @author Alexey Sukhotin
**/
- protected function imgSquareFit($path, $width, $height, $align = 'center', $valign = 'middle', $bgcolor = '#0000ff', $destformat = null) {
+ protected function imgSquareFit($path, $width, $height, $align = 'center', $valign = 'middle', $bgcolor = '#0000ff', $destformat = null) {
if (($s = @getimagesize($path)) == false) {
return false;
}
@@ -2831,11 +2842,9 @@ abstract class elFinderVolumeDriver {
switch ($this->imgLib) {
case 'imagick':
-
try {
$img = new imagick($path);
} catch (Exception $e) {
-
return false;
}
@@ -2879,7 +2888,7 @@ abstract class elFinderVolumeDriver {
if (!imagecopy($tmp, $img, $x, $y, 0, 0, $s[0], $s[1])) {
return false;
}
-
+
if ($destformat == 'jpg' || ($destformat == null && $s['mime'] == 'image/jpeg')) {
$result = imagejpeg($tmp, $path, 100);
} else if ($destformat == 'gif' || ($destformat == null && $s['mime'] == 'image/gif')) {
@@ -2892,14 +2901,80 @@ abstract class elFinderVolumeDriver {
imagedestroy($tmp);
return $result ? $path : false;
-
}
break;
}
- return false;
- }
-
+ return false;
+ }
+
+ /**
+ * Rotate image
+ *
+ * @param string $path image file
+ * @param int $degree rotete degrees
+ * @param string $bgcolor square background color in #rrggbb format
+ * @param string $destformat image destination format
+ * @return string|false
+ * @author nao-pon
+ * @author Troex Nevelin
+ **/
+ protected function imgRotate($path, $degree, $bgcolor = '#ffffff', $destformat = null) {
+ if (($s = @getimagesize($path)) == false) {
+ return false;
+ }
+
+ $result = false;
+
+ switch ($this->imgLib) {
+ case 'imagick':
+ try {
+ $img = new imagick($path);
+ } catch (Exception $e) {
+ return false;
+ }
+
+ $img->rotateImage(new ImagickPixel($bgcolor), $degree);
+ $result = $img->writeImage($path);
+ return $result ? $path : false;
+
+ break;
+
+ case 'gd':
+ if ($s['mime'] == 'image/jpeg') {
+ $img = imagecreatefromjpeg($path);
+ } elseif ($s['mime'] == 'image/png') {
+ $img = imagecreatefrompng($path);
+ } elseif ($s['mime'] == 'image/gif') {
+ $img = imagecreatefromgif($path);
+ } elseif ($s['mime'] == 'image/xbm') {
+ $img = imagecreatefromxbm($path);
+ }
+
+ $degree = 360 - $degree;
+ list($r, $g, $b) = sscanf($bgcolor, "#%02x%02x%02x");
+ $bgcolor = imagecolorallocate($img, $r, $g, $b);
+ $tmp = imageRotate($img, $degree, (int)$bgcolor);
+
+ if ($destformat == 'jpg' || ($destformat == null && $s['mime'] == 'image/jpeg')) {
+ $result = imagejpeg($tmp, $path, 100);
+ } else if ($destformat == 'gif' || ($destformat == null && $s['mime'] == 'image/gif')) {
+ $result = imagegif($tmp, $path, 7);
+ } else {
+ $result = imagepng($tmp, $path, 7);
+ }
+
+ imageDestroy($img);
+ imageDestroy($tmp);
+
+ return $result ? $path : false;
+
+ break;
+ }
+
+ return false;
+ }
+
/**
* Execute shell command
*
diff --git a/php/elFinderVolumeMySQL.class.php b/php/elFinderVolumeMySQL.class.php
index a540ca277..1a17c71d5 100644
--- a/php/elFinderVolumeMySQL.class.php
+++ b/php/elFinderVolumeMySQL.class.php
@@ -231,7 +231,7 @@ class elFinderVolumeMySQL extends elFinderVolumeDriver {
* @author Dmitry (dio) Levashov
* @author Alexey Sukhotin
**/
- public function resize($hash, $width, $height, $x, $y, $mode = 'resize', $bg='') {
+ public function resize($hash, $width, $height, $x, $y, $mode = 'resize', $bg = '', $degree = 0) {
if ($this->commandDisabled('resize')) {
return $this->setError(elFinder::ERROR_PERM_DENIED);
}