: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @class elFinder command "resize"
* Open dialog to resize image
* @author Dmitry (dio) Levashov
* @author Alexey Sukhotin
elFinder.prototype.commands.resize = function() {
getBounceBox = function(w, h, theta) {
min = {x: Number.MAX_VALUE, y: Number.MAX_VALUE},
max = {x: Number.MIN_VALUE, y: Number.MIN_VALUE};
jQuery.each(srcPts, function(i, srcPt){
x: srcPt.x * Math.cos(theta) - srcPt.y * Math.sin(theta),
y: srcPt.x * Math.sin(theta) + srcPt.y * Math.cos(theta)
jQuery.each(dstPts, function(i, pt) {
min.x = Math.min(min.x, pt.x);
min.y = Math.min(min.y, pt.y);
max.x = Math.max(max.x, pt.x);
max.y = Math.max(max.y, pt.y);
width: max.x - min.x, height: max.y - min.y
this.updateOnSelect = false;
this.getstate = function() {
var sel = fm.selectedFiles();
return sel.length == 1 && sel[0].read && sel[0].write && sel[0].mime.indexOf('image/') !== -1 ? 0 : -1;
this.resizeRequest = function(data, f, dfrd) {
var file = f || fm.file(data.target),
tmb = file? file.tmb : null,
enabled = fm.isCommandEnabled('resize', data.target);
if (enabled && (! file || (file && file.read && file.write && file.mime.indexOf('image/') !== -1 ))) {
data : Object.assign(data, {
notify : {type : 'resize', cnt : 1}
fm.storage('jpgQuality', data.quality === fm.option('jpgQuality')? null : data.quality);
if (file.mime.indexOf('image/') === -1) {
error = ['errResize', file.name, 'errUsupportType'];
error = ['errResize', file.name, 'errPerm'];
error = ['errResize', data.target, 'errPerm'];
return jQuery.Deferred().reject(error);
this.exec = function(hashes) {
files = this.files(hashes),
dfrd = jQuery.Deferred(),
ctrgrup = jQuery().controlgroup? 'controlgroup' : 'buttonset',
grid8Def = typeof options.grid8px === 'undefined' || options.grid8px !== 'disable'? true : false,
presetSize = Array.isArray(options.presetSize)? options.presetSize : [],
clactive = 'elfinder-dialog-active',
clsediting = fm.res('class', 'editing'),
open = function(file, id, src) {
var isJpeg = (file.mime === 'image/jpeg'),
dialog = jQuery('<div class="elfinder-resize-container"></div>'),
input = '<input type="number" class="ui-corner-all"/>',
row = '<div class="elfinder-resize-row"></div>',
label = '<div class="elfinder-resize-label"></div>',
opStart = function() { operate = true; },
control.trigger('change');
control = jQuery('<div class="elfinder-resize-control"></div>')
.on('focus', 'input[type=text],input[type=number]', function() {
jQuery(this).trigger('select');
.on('change', function() {
changeTm && cancelAnimationFrame(changeTm);
changeTm = requestAnimationFrame(function() {
var panel, quty, canvas, ctx, img, sx, sy, sw, sh, deg, theta, bb;
if (sizeImg && ! operate && (canvas = sizeImg.data('canvas'))) {
panel = control.children('div.elfinder-resize-control-panel:visible');
quty = panel.find('input.elfinder-resize-quality');
if (quty.is(':visible')) {
ctx = sizeImg.data('ctx');
if (panel.hasClass('elfinder-resize-uiresize')) {
sw = canvas.width = width.val();
sh = canvas.height = height.val();
ctx.drawImage(img, 0, 0, sw, sh);
} else if (panel.hasClass('elfinder-resize-uicrop')) {
ctx.drawImage(img, sx, sy, sw, sh, 0, 0, sw, sh);
theta = (degree.val() * Math.PI) / 180;
bb = getBounceBox(owidth, oheight, theta);
sw = canvas.width = bb.width;
sh = canvas.height = bb.height;
ctx.fillStyle = bg.val() || '#FFF';
ctx.fillRect(0, 0, sw, sh);
ctx.translate(sw / 2, sh / 2);
ctx.drawImage(img, -img.width/2, -img.height/2, owidth, oheight);
canvas.toBlob(function(blob) {
quty.next('span').text(' (' + fm.formatSize(blob.size) + ')');
}, 'image/jpeg', Math.max(Math.min(quty.val(), 100), 1) / 100);
.on('mouseup', 'input', function(e) {
jQuery(e.target).trigger('change');
preview = jQuery('<div class="elfinder-resize-preview"></div>')
.on('touchmove', function(e) {
if (jQuery(e.target).hasClass('touch-punch')) {
spinner = jQuery('<div class="elfinder-resize-loading">'+fm.i18n('ntfloadimg')+'</div>'),
rhandle = jQuery('<div class="elfinder-resize-handle touch-punch"></div>'),
rhandlec = jQuery('<div class="elfinder-resize-handle touch-punch"></div>'),
uiresize = jQuery('<div class="elfinder-resize-uiresize elfinder-resize-control-panel"></div>'),
uicrop = jQuery('<div class="elfinder-resize-uicrop elfinder-resize-control-panel"></div>'),
uirotate = jQuery('<div class="elfinder-resize-rotate elfinder-resize-control-panel"></div>'),
uideg270 = jQuery('<button></button>').attr('title',fm.i18n('rotate-cw')).append(jQuery('<span class="elfinder-button-icon elfinder-button-icon-rotate-l"></span>')),
uideg90 = jQuery('<button></button>').attr('title',fm.i18n('rotate-ccw')).append(jQuery('<span class="elfinder-button-icon elfinder-button-icon-rotate-r"></span>')),
uiprop = jQuery('<span ></span>'),
reset = jQuery('<button class="elfinder-resize-reset">').text(fm.i18n('reset'))
.on('click', function() {
primary: 'ui-icon-arrowrefresh-1-n'
uitype = jQuery('<div class="elfinder-resize-type"></div>')
.append('<input type="radio" name="type" id="'+id+'-resize" value="resize" checked="checked" /><label for="'+id+'-resize">'+fm.i18n('resize')+'</label>',
'<input class="api2" type="radio" name="type" id="'+id+'-crop" value="crop" /><label class="api2" for="'+id+'-crop">'+fm.i18n('crop')+'</label>',
'<input class="api2" type="radio" name="type" id="'+id+'-rotate" value="rotate" /><label class="api2" for="'+id+'-rotate">'+fm.i18n('rotate')+'</label>'),
type = uitype[ctrgrup]()[ctrgrup]('disable').find('input')
.on('change', function() {
mode = jQuery(this).val();
isJpeg && grid8px.insertAfter(uiresize.find('.elfinder-resize-grid8'));
else if (mode == 'crop') {
isJpeg && grid8px.insertAfter(uicrop.find('.elfinder-resize-grid8'));
} else if (mode == 'rotate') {
.on('change', function() {
var w = round(parseInt(width.val())),
h = round(cratio ? w/ratio : parseInt(height.val()));
}).addClass('elfinder-focus'),
.on('change', function() {
var h = round(parseInt(height.val())),
w = round(cratio ? h*ratio : parseInt(width.val()));
pointX = jQuery(input).on('change', function(){crop.updateView();}),
pointY = jQuery(input).on('change', function(){crop.updateView();}),
offsetX = jQuery(input).on('change', function(){crop.updateView('w');}),
offsetY = jQuery(input).on('change', function(){crop.updateView('h');}),
quality = isJpeg && api2?
jQuery(input).val(fm.storage('jpgQuality') > 0? fm.storage('jpgQuality') : fm.option('jpgQuality'))
.addClass('elfinder-resize-quality')
.attr('min', '1').attr('max', '100').attr('title', '1 - 100')
var q = Math.min(100, Math.max(1, parseInt(this.value)));
control.find('input.elfinder-resize-quality').val(q);
degree = jQuery('<input type="number" class="ui-corner-all" maxlength="3" value="0" />')
.on('change', function() {
uidegslider = jQuery('<div class="elfinder-resize-rotate-slider touch-punch"></div>')
change: function(event, ui) {
if (ui.value != uidegslider.slider('value')) {
slide: function(event, ui) {
rotate.update(ui.value, false);
}).find('.ui-slider-handle')
.addClass('elfinder-tabstop')
.on('keydown', function(e) {
if (e.keyCode == jQuery.ui.keyCode.LEFT || e.keyCode == jQuery.ui.keyCode.RIGHT) {
rotate.update(Number(degree.val()) + (e.keyCode == jQuery.ui.keyCode.RIGHT? 1 : -1), false);
var color, r, g, b, h, s, l;
color = pickc[Math.round(e.offsetX)][Math.round(e.offsetY)];
r = color[0]; g = color[1]; b = color[2];
h = color[3]; s = color[4]; l = color[5];
setbg(r, g, b, (e.type === 'click'));
setbg(jQuery(this).css('backgroundColor'), '', '', (e.type === 'click'));
setbg = function(r, g, b, off) {
if (typeof r === 'string') {
if (r && (s = jQuery('<span>').css('backgroundColor', r).css('backgroundColor')) && (m = s.match(/rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i))) {
cc = (g === '')? r : '#' + getColorCode(r, g, b);
bg.val(cc).css({ backgroundColor: cc, backgroundImage: 'none', color: (r+g+b < 384? '#fff' : '#000') });
preview.css('backgroundColor', cc);
imgr.off('.picker').removeClass('elfinder-resize-picking');
pallet.off('.picker').removeClass('elfinder-resize-picking');
getColorCode = function(r, g, b) {
return jQuery.map([r,g,b], function(c){return ('0'+parseInt(c).toString(16)).slice(-2);}).join('');
picker = jQuery('<button>').text(fm.i18n('colorPicker'))
.on('click', function() {
imgr.on('mousemove.picker click.picker', pick).addClass('elfinder-resize-picking');
pallet.on('mousemove.picker click.picker', 'span', palpick).addClass('elfinder-resize-picking');
reseter = jQuery('<button>').text(fm.i18n('reset'))
.on('click', function() {
primary: 'ui-icon-arrowrefresh-1-n'
bg = jQuery('<input class="ui-corner-all elfinder-resize-bg" type="text">')
.on('focus', function() {
jQuery(this).attr('style', '');
setbg(jQuery(this).val());
pallet = jQuery('<div class="elfinder-resize-pallet">').on('click', 'span', function() {
setbg(jQuery(this).css('backgroundColor'));
grid8 = isJpeg? grid8Def : false,
constr = jQuery('<button>').html(fm.i18n('aspectRatio'))
.on('click', function() {
constr.button('option', {
icons : { primary: cratio? 'ui-icon-locked' : 'ui-icon-unlocked'}
rhandle.resizable('option', 'aspectRatio', cratio).data('uiResizable')._aspectRatio = cratio;
primary: cratio? 'ui-icon-locked' : 'ui-icon-unlocked'
constrc = jQuery('<button>').html(fm.i18n('aspectRatio'))
.on('click', function() {
constrc.button('option', {
icons : { primary: cratioc? 'ui-icon-locked' : 'ui-icon-unlocked'}
rhandlec.resizable('option', 'aspectRatio', cratioc).data('uiResizable')._aspectRatio = cratioc;
primary: cratioc? 'ui-icon-locked' : 'ui-icon-unlocked'
grid8px = jQuery('<button>').html(fm.i18n(grid8? 'enabled' : 'disabled')).toggleClass('ui-state-active', grid8)
.on('click', function() {
grid8px.html(fm.i18n(grid8? 'enabled' : 'disabled')).toggleClass('ui-state-active', grid8);
jQuery.each([width, height, offsetX, offsetY, pointX, pointY], function() {
width.val(round(width.val()));
height.val(round(height.val()));
offsetX.val(round(offsetX.val()));
offsetY.val(round(offsetY.val()));
pointX.val(round(pointX.val()));
pointY.val(round(pointY.val()));
if (uiresize.is(':visible')) {
resize.updateView(width.val(), height.val());
} else if (uicrop.is(':visible')) {
r_scale = Math.min(pwidth, pheight) / Math.sqrt(Math.pow(owidth, 2) + Math.pow(oheight, 2));
rwidth = Math.ceil(owidth * r_scale);
rheight = Math.ceil(oheight * r_scale);
.css('margin-top', (pheight-rheight)/2 + 'px')
.css('margin-left', (pwidth-rwidth)/2 + 'px');
if (imgr.is(':visible') && bg.is(':visible')) {
if (file.mime !== 'image/png') {
preview.css('backgroundColor', bg.val());
pickimg = jQuery('<img>');
pickimg.attr('crossorigin', 'use-credentials');
pickimg.on('load', function() {
if (pickcanv && pickcanv.width !== rwidth) {
resize.updateView(owidth, oheight);
setColorData = function() {
var n, w, h, r, g, b, a, s, l, hsl, hue,
data, scale, tx1, tx2, ty1, ty2, rgb,
rgbToHsl = function (r, g, b) {
max = Math.max(Math.max(r, g), b),
min = Math.min(Math.min(r, g), b);