diff --git a/css/toolbar.css b/css/toolbar.css
index 8ece0cbbc..dd7bc04e2 100644
--- a/css/toolbar.css
+++ b/css/toolbar.css
@@ -108,8 +108,9 @@
.elfinder-button-icon-help { background-position: 0 -480px; }
.elfinder-button-icon-resize { background-position: 0 -512px; }
.elfinder-button-icon-search { background-position: 0 -561px; }
-.elfinder-button-icon-sort { background-position: 0 -577px; }
-
+.elfinder-button-icon-sort { background-position: 0 -577px; }
+.elfinder-button-icon-rotate-r { background-position: 0 -625px; }
+.elfinder-button-icon-rotate-l { background-position: 0 -641px; }
/* button with dropdown menu*/
.elfinder .elfinder-menubutton { overflow:visible; }
diff --git a/img/toolbar.png b/img/toolbar.png
index ddfb9bc6f..3b51326db 100644
Binary files a/img/toolbar.png and b/img/toolbar.png differ
diff --git a/js/commands/resize.js b/js/commands/resize.js
index a4c602494..d8f98aea4 100644
--- a/js/commands/resize.js
+++ b/js/commands/resize.js
@@ -31,17 +31,41 @@ elFinder.prototype.commands.resize = function() {
rhandlec = $('
'),
uiresize = $(''),
uicrop = $(''),
+ uibuttonset = '',
+ uibutton = '',
+ uiseparator = '',
+ uirotate = $(''),
+ uideg270 = $(uibutton).attr('title',fm.i18n('rotate-cw')).append($('')
+ .click(function(){
+ var val = (parseInt(degree.val()) || 0) - 90;
+ //val = parseInt(val / 90) * 90;
+ if (val < 0) {
+ val = 360 + val;
+ }
+ degree.val(val);
+ })),
+ uideg90 = $(uibutton).attr('title',fm.i18n('rotate-ccw')).append($('')
+ .click(function(){
+ var val = (parseInt(degree.val()) || 0) + 90;
+ //val = parseInt(val / 90) * 90;
+ if (val >= 360) {
+ val = val - 360;
+ }
+ degree.val(val);
+ })),
uiprop = $(''),
reset = $('
'),
uitype = $('')
- .append('')
- .append(''),
+ .append('')
+ .append('')
+ .append(''),
type = $('input', uitype)
.change(function() {
uiresize.add(uicrop).toggle();
resetView();
resizable(true);
croppable(true);
+ // TODO rotateable
var val = $('input:checked', uitype).val();
if (val == 'resize') {
@@ -82,6 +106,7 @@ elFinder.prototype.commands.resize = function() {
pointY = $(input),
offsetX = $(input),
offsetY = $(input),
+ degree = $(''),
ratio = 1,
prop = 1,
owidth = 0,
@@ -95,7 +120,7 @@ elFinder.prototype.commands.resize = function() {
owidth = img.width();
oheight = img.height();
- ratio = (owidth/oheight).toFixed(2);
+ ratio = owidth/oheight;
resize.updateView(owidth, oheight);
rhandle.append(img.show()).show();
@@ -246,7 +271,7 @@ elFinder.prototype.commands.resize = function() {
}
},
save = function() {
- var w, h, x, y;
+ var w, h, x, y, d;
var mode = $('input:checked', uitype).val();
width.add(height).change();
@@ -259,6 +284,13 @@ elFinder.prototype.commands.resize = function() {
h = parseInt(offsetY.val()) || 0;
x = parseInt(pointX.val()) || 0;
y = parseInt(pointY.val()) || 0;
+ } else if (mode = 'rotate') {
+ w = parseInt(offsetX.val()) || 0;
+ h = parseInt(offsetY.val()) || 0;
+ d = parseInt(degree.val()) || 0;
+ if (d < 0 || d > 360) {
+ return fm.error('Invalid rotate degree');
+ }
}
if (w <= 0 || h <= 0) {
@@ -279,6 +311,7 @@ elFinder.prototype.commands.resize = function() {
height : h,
x : x,
y : y,
+ degree : d,
mode : mode
},
notify : {type : 'resize', cnt : 1}
@@ -307,13 +340,22 @@ elFinder.prototype.commands.resize = function() {
uicrop.append($(row).append($(label).text('X')).append(pointX))
.append($(row).append($(label).text('Y')).append(pointY))
.append($(row).append($(label).text(fm.i18n('width'))).append(offsetX))
- .append($(row).append($(label).text(fm.i18n('height'))).append(offsetY))
+ .append($(row).append($(label).text(fm.i18n('height'))).append(offsetY));
+
+ uirotate.append($(row)
+ .append($(label).text(fm.i18n('rotate')))
+ .append($('')
+ .append(degree)
+ .append($('
').text(fm.i18n('degree')))
+ ).append($(uibuttonset).append(uideg270).append($(uiseparator)).append(uideg90))
+ );
dialog.append(uitype);
control.append($(row))
.append(uiresize)
.append(uicrop.hide())
+ .append(uirotate.hide())
.find('input,select').attr('disabled', 'disabled');
rhandle.append('
')
diff --git a/js/i18n/elfinder.en.js b/js/i18n/elfinder.en.js
index 9e1fd8f57..2be7105ea 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,13 @@ if (elFinder && elFinder.prototype && typeof(elFinder.prototype.i18) == 'object'
'scale' : 'Scale',
'width' : 'Width',
'height' : 'Height',
- 'mode' : 'Mode',
- 'resize' : 'Resize',
- 'crop' : 'Crop',
+ 'mode' : 'Mode',
+ 'resize' : 'Resize',
+ 'crop' : 'Crop',
+ 'rotate' : 'Rotate',
+ 'rotate-l90' : '90-degree left rotation',
+ 'rotate-r90' : '90-degree right rotation',
+ 'deg' : 'Deg',
/********************************** mimetypes **********************************/
'kindUnknown' : 'Unknown',
diff --git a/js/i18n/elfinder.jp.js b/js/i18n/elfinder.jp.js
index 2cab79c8a..d8b96d905 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 ***********************************/
@@ -229,6 +229,10 @@ if (elFinder && elFinder.prototype && typeof(elFinder.prototype.i18) == 'object'
'mode' : 'モード',
'resize' : 'リサイズ',
'crop' : '切り抜き',
+ 'rotate' : '回転',
+ 'rotate-l90' : '90度左回転',
+ 'rotate-r90' : '90度右回転',
+ 'deg' : '度',
/********************************** mimetypes **********************************/
'kindUnknown' : '不明',
diff --git a/php/elFinder.class.php b/php/elFinder.class.php
index 2de5260dc..2d07327f4 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 18eebcefd..a264fa9cf 100644
--- a/php/elFinderVolumeDriver.class.php
+++ b/php/elFinderVolumeDriver.class.php
@@ -1601,12 +1601,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);
}
@@ -1636,14 +1640,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']);
@@ -2612,7 +2620,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) {
@@ -2718,7 +2727,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) {
@@ -2793,9 +2803,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;
}
@@ -2808,11 +2819,9 @@ abstract class elFinderVolumeDriver {
switch ($this->imgLib) {
case 'imagick':
-
try {
$img = new imagick($path);
} catch (Exception $e) {
-
return false;
}
@@ -2856,7 +2865,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')) {
@@ -2869,14 +2878,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
*