added cropping support
This commit is contained in:
parent
5ec89293b2
commit
137ef0721f
|
@ -208,5 +208,6 @@ templates/lib/*jquery*.js B 2010 John Resig, Paul Bakaus, Fr
|
|||
templates/lib/*jquery-dropmenu-*.js B 2010 Fred Heusschen
|
||||
templates/lib/*jquery-validationEngine-*.js B 2010 Cedric Dugas and Olivier Refalo
|
||||
templates/lib/*jquery-fineuploader-*.js B 2010 Andrew Valums
|
||||
|
||||
templates/lib/extra/cropperjs B 2018 Chen Fengyuan
|
||||
style/600_cropper.css B 2018 Chen Fengyuan
|
||||
|
||||
|
|
|
@ -2543,6 +2543,8 @@ class htmlImage extends htmlElement {
|
|||
private $title;
|
||||
/** onClick event */
|
||||
private $onClick = null;
|
||||
/** enable cropping */
|
||||
private $crop = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
|
@ -2553,7 +2555,7 @@ class htmlImage extends htmlElement {
|
|||
* @param String $alt alt text (optional)
|
||||
* @param String $onClick onClick code (optional)
|
||||
*/
|
||||
function __construct($path, $width = null, $height = null, $alt = ' ', $title = null, $onClick = null) {
|
||||
public function __construct($path, $width = null, $height = null, $alt = ' ', $title = null, $onClick = null) {
|
||||
$this->path = htmlspecialchars($path);
|
||||
$this->width = $width;
|
||||
$this->height = $height;
|
||||
|
@ -2573,7 +2575,7 @@ class htmlImage extends htmlElement {
|
|||
* @param string $scope Account type
|
||||
* @return array List of input field names and their type (name => type)
|
||||
*/
|
||||
function generateHTML($module, $input, $values, $restricted, &$tabindex, $scope) {
|
||||
public function generateHTML($module, $input, $values, $restricted, &$tabindex, $scope) {
|
||||
$path = ' src="' . $this->path . '"';
|
||||
$width = '';
|
||||
if ($this->width != null) {
|
||||
|
@ -2588,6 +2590,9 @@ class htmlImage extends htmlElement {
|
|||
if (!empty($this->title)) {
|
||||
$title = ' title="' . $this->title . '"';
|
||||
}
|
||||
if ($this->crop) {
|
||||
$this->cssClasses[] = 'cropperjsImage';
|
||||
}
|
||||
$classes = '';
|
||||
if (!empty($this->cssClasses)) {
|
||||
$classes = 'class="' . implode(' ', $this->cssClasses) . '"';
|
||||
|
@ -2597,9 +2602,46 @@ class htmlImage extends htmlElement {
|
|||
$onClick = ' onclick="' . $this->onClick . '"';
|
||||
}
|
||||
echo '<img' . $path . $width . $height . $alt . $title . $classes . $onClick . ">";
|
||||
if ($this->crop) {
|
||||
$cropJsPath = 'templates/lib/extra/cropperjs/cropper.js';
|
||||
if (is_file('../../templates/login.php')) {
|
||||
$cropJsPath = '../../' . $cropJsPath;
|
||||
}
|
||||
else {
|
||||
$cropJsPath = '../' . $cropJsPath;
|
||||
}
|
||||
echo '<script type="text/javascript" src="' . $cropJsPath . '"></script>';
|
||||
echo '<script type="text/javascript">
|
||||
var image = jQuery(\'.cropperjsImage\')[0];
|
||||
var cropper = new Cropper(image, {
|
||||
viewMode: 1,
|
||||
movable: false,
|
||||
zoomable: false,
|
||||
crop: function(event) {
|
||||
jQuery(\'#croppingDataX\').val(event.detail.x);
|
||||
jQuery(\'#croppingDataY\').val(event.detail.y);
|
||||
jQuery(\'#croppingDataWidth\').val(event.detail.width);
|
||||
jQuery(\'#croppingDataHeight\').val(event.detail.height);
|
||||
}
|
||||
});
|
||||
</script>';
|
||||
echo '<input id="croppingDataX" type="hidden" name="croppingDataX" value="0"/>';
|
||||
echo '<input id="croppingDataY" type="hidden" name="croppingDataY" value="0"/>';
|
||||
echo '<input id="croppingDataWidth" type="hidden" name="croppingDataWidth" value="0"/>';
|
||||
echo '<input id="croppingDataHeight" type="hidden" name="croppingDataHeight" value="0"/>';
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables cropping feature.
|
||||
* This will display a cropping box on the image. The cropping data
|
||||
* can be found in POST data (croppingDataX, croppingDataY, croppingDataWidth, croppingDataHeight).
|
||||
*/
|
||||
public function enableCropping() {
|
||||
$this->crop = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1607,15 +1607,43 @@ class inetOrgPerson extends baseModule implements passwordService {
|
|||
|
||||
/**
|
||||
* Sets a new photo.
|
||||
*
|
||||
* @return array list of error messages if any
|
||||
*/
|
||||
function process_photo() {
|
||||
if (!isset($_POST['form_subpage_' . get_class($this) . '_attributes_submit'])) {
|
||||
public function process_photo() {
|
||||
if (isset($_POST['form_subpage_' . get_class($this) . '_attributes_back'])) {
|
||||
return array();
|
||||
}
|
||||
$messages = array();
|
||||
if ($this->isAdminReadOnly('jpegPhoto')) {
|
||||
return array();
|
||||
}
|
||||
if (isset($_POST['form_subpage_' . get_class($this) . '_photo_upload'])) {
|
||||
return $this->uploadPhoto();
|
||||
}
|
||||
if (isset($_POST['form_subpage_' . get_class($this) . '_attributes_crop'])) {
|
||||
$messages = array();
|
||||
$image = new Imagick();
|
||||
try {
|
||||
$image->readImageBlob($this->attributes['jpegPhoto'][0]);
|
||||
$image->cropimage($_POST['croppingDataWidth'], $_POST['croppingDataHeight'], $_POST['croppingDataX'], $_POST['croppingDataY']);
|
||||
$this->attributes['jpegPhoto'][0] = $image->getimageblob();
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$msg = $this->messages['file'][2];
|
||||
$msg[] = htmlspecialchars($e->getMessage());
|
||||
$messages[] = $msg;
|
||||
}
|
||||
return $messages;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads the photo file.
|
||||
*
|
||||
* @return array error messages if any
|
||||
*/
|
||||
private function uploadPhoto() {
|
||||
$messages = array();
|
||||
if ($_FILES['photoFile'] && ($_FILES['photoFile']['size'] > 0)) {
|
||||
$name = $_FILES['photoFile']['name'];
|
||||
$extension = strtolower(substr($name, strpos($name, '.') + 1));
|
||||
|
@ -1628,7 +1656,7 @@ class inetOrgPerson extends baseModule implements passwordService {
|
|||
return array($errMsg);
|
||||
}
|
||||
fclose($handle);
|
||||
// convert to JPG if imagick extension is available
|
||||
// convert to JPG
|
||||
$image = new Imagick();
|
||||
try {
|
||||
$image->readImageBlob($data);
|
||||
|
@ -1661,14 +1689,34 @@ class inetOrgPerson extends baseModule implements passwordService {
|
|||
*
|
||||
* @return array meta HTML code
|
||||
*/
|
||||
function display_html_photo() {
|
||||
public function display_html_photo() {
|
||||
$container = new htmlTable();
|
||||
if (empty($this->attributes['jpegPhoto'][0])) {
|
||||
$container->addElement(new htmlSubTitle(_('Upload image')), true);
|
||||
$label = _('Photo file');
|
||||
$container->addElement(new htmlTableExtendedInputFileUpload('photoFile', $label, 'photoUpload'), true);
|
||||
$container->addVerticalSpace('1rem');
|
||||
$buttonContainer = new htmlTable();
|
||||
$buttonContainer->addElement(new htmlAccountPageButton(get_class($this), 'attributes', 'submit', _('Add photo')));
|
||||
$buttonContainer->addElement(new htmlAccountPageButton(get_class($this), 'photo', 'upload', _('Upload')));
|
||||
$buttonContainer->addElement(new htmlAccountPageButton(get_class($this), 'attributes', 'back', _('Back')));
|
||||
$container->addElement($buttonContainer);
|
||||
}
|
||||
else {
|
||||
$container->addElement(new htmlSubTitle(_('Crop image')), true);
|
||||
$jpeg_filename = 'jpg' . getRandomNumber() . '.jpg';
|
||||
$outjpeg = @fopen(dirname(__FILE__) . '/../../tmp/' . $jpeg_filename, "wb");
|
||||
fwrite($outjpeg, $this->attributes['jpegPhoto'][0]);
|
||||
fclose ($outjpeg);
|
||||
$photoFile = '../../tmp/' . $jpeg_filename;
|
||||
$img = new htmlImage($photoFile);
|
||||
$img->setCSSClasses(array('photo'));
|
||||
$img->enableCropping();
|
||||
$container->addElement($img, true);
|
||||
$container->addVerticalSpace('1rem');
|
||||
$buttonContainer = new htmlTable();
|
||||
$buttonContainer->addElement(new htmlAccountPageButton(get_class($this), 'attributes', 'crop', _('Done')));
|
||||
$container->addElement($buttonContainer, true);
|
||||
}
|
||||
return $container;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,305 @@
|
|||
/*!
|
||||
* Cropper.js v1.3.5
|
||||
* https://github.com/fengyuanchen/cropperjs
|
||||
*
|
||||
* Copyright (c) 2015-2018 Chen Fengyuan
|
||||
* Released under the MIT license
|
||||
*
|
||||
* Date: 2018-04-15T06:19:56.029Z
|
||||
*/
|
||||
|
||||
.cropper-container {
|
||||
direction: ltr;
|
||||
font-size: 0;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.cropper-container img {/*Avoid margin top issue (Occur only when margin-top <= -height)
|
||||
*/
|
||||
display: block;
|
||||
height: 100%;
|
||||
image-orientation: 0deg;
|
||||
max-height: none !important;
|
||||
max-width: none !important;
|
||||
min-height: 0 !important;
|
||||
min-width: 0 !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cropper-wrap-box,
|
||||
.cropper-canvas,
|
||||
.cropper-drag-box,
|
||||
.cropper-crop-box,
|
||||
.cropper-modal {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.cropper-wrap-box,
|
||||
.cropper-canvas {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.cropper-drag-box {
|
||||
background-color: #fff;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.cropper-modal {
|
||||
background-color: #000;
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.cropper-view-box {
|
||||
display: block;
|
||||
height: 100%;
|
||||
outline-color: rgba(51, 153, 255, 0.75);
|
||||
outline: 1px solid #39f;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cropper-dashed {
|
||||
border: 0 dashed #eee;
|
||||
display: block;
|
||||
opacity: .5;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.cropper-dashed.dashed-h {
|
||||
border-bottom-width: 1px;
|
||||
border-top-width: 1px;
|
||||
height: 33.33333%;
|
||||
left: 0;
|
||||
top: 33.33333%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cropper-dashed.dashed-v {
|
||||
border-left-width: 1px;
|
||||
border-right-width: 1px;
|
||||
height: 100%;
|
||||
left: 33.33333%;
|
||||
top: 0;
|
||||
width: 33.33333%;
|
||||
}
|
||||
|
||||
.cropper-center {
|
||||
display: block;
|
||||
height: 0;
|
||||
left: 50%;
|
||||
opacity: .75;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.cropper-center:before,
|
||||
.cropper-center:after {
|
||||
background-color: #eee;
|
||||
content: ' ';
|
||||
display: block;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.cropper-center:before {
|
||||
height: 1px;
|
||||
left: -3px;
|
||||
top: 0;
|
||||
width: 7px;
|
||||
}
|
||||
|
||||
.cropper-center:after {
|
||||
height: 7px;
|
||||
left: 0;
|
||||
top: -3px;
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
.cropper-face,
|
||||
.cropper-line,
|
||||
.cropper-point {
|
||||
display: block;
|
||||
height: 100%;
|
||||
opacity: .1;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cropper-face {
|
||||
background-color: #fff;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.cropper-line {
|
||||
background-color: #39f;
|
||||
}
|
||||
|
||||
.cropper-line.line-e {
|
||||
cursor: ew-resize;
|
||||
right: -3px;
|
||||
top: 0;
|
||||
width: 5px;
|
||||
}
|
||||
|
||||
.cropper-line.line-n {
|
||||
cursor: ns-resize;
|
||||
height: 5px;
|
||||
left: 0;
|
||||
top: -3px;
|
||||
}
|
||||
|
||||
.cropper-line.line-w {
|
||||
cursor: ew-resize;
|
||||
left: -3px;
|
||||
top: 0;
|
||||
width: 5px;
|
||||
}
|
||||
|
||||
.cropper-line.line-s {
|
||||
bottom: -3px;
|
||||
cursor: ns-resize;
|
||||
height: 5px;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.cropper-point {
|
||||
background-color: #39f;
|
||||
height: 5px;
|
||||
opacity: .75;
|
||||
width: 5px;
|
||||
}
|
||||
|
||||
.cropper-point.point-e {
|
||||
cursor: ew-resize;
|
||||
margin-top: -3px;
|
||||
right: -3px;
|
||||
top: 50%;
|
||||
}
|
||||
|
||||
.cropper-point.point-n {
|
||||
cursor: ns-resize;
|
||||
left: 50%;
|
||||
margin-left: -3px;
|
||||
top: -3px;
|
||||
}
|
||||
|
||||
.cropper-point.point-w {
|
||||
cursor: ew-resize;
|
||||
left: -3px;
|
||||
margin-top: -3px;
|
||||
top: 50%;
|
||||
}
|
||||
|
||||
.cropper-point.point-s {
|
||||
bottom: -3px;
|
||||
cursor: s-resize;
|
||||
left: 50%;
|
||||
margin-left: -3px;
|
||||
}
|
||||
|
||||
.cropper-point.point-ne {
|
||||
cursor: nesw-resize;
|
||||
right: -3px;
|
||||
top: -3px;
|
||||
}
|
||||
|
||||
.cropper-point.point-nw {
|
||||
cursor: nwse-resize;
|
||||
left: -3px;
|
||||
top: -3px;
|
||||
}
|
||||
|
||||
.cropper-point.point-sw {
|
||||
bottom: -3px;
|
||||
cursor: nesw-resize;
|
||||
left: -3px;
|
||||
}
|
||||
|
||||
.cropper-point.point-se {
|
||||
bottom: -3px;
|
||||
cursor: nwse-resize;
|
||||
height: 20px;
|
||||
opacity: 1;
|
||||
right: -3px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.cropper-point.point-se {
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.cropper-point.point-se {
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.cropper-point.point-se {
|
||||
height: 5px;
|
||||
opacity: .75;
|
||||
width: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.cropper-point.point-se:before {
|
||||
background-color: #39f;
|
||||
bottom: -50%;
|
||||
content: ' ';
|
||||
display: block;
|
||||
height: 200%;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
right: -50%;
|
||||
width: 200%;
|
||||
}
|
||||
|
||||
.cropper-invisible {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.cropper-bg {
|
||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC');
|
||||
}
|
||||
|
||||
.cropper-hide {
|
||||
display: block;
|
||||
height: 0;
|
||||
position: absolute;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.cropper-hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.cropper-move {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.cropper-crop {
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.cropper-disabled .cropper-drag-box,
|
||||
.cropper-disabled .cropper-face,
|
||||
.cropper-disabled .cropper-line,
|
||||
.cropper-disabled .cropper-point {
|
||||
cursor: not-allowed;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue