Редактор изображений на cropper.js

Создаем web-part, подключаем скрипты

<script src="/_layouts/15/cropper/cropper.js"></script>
<link href="/_layouts/15/cropper/cropper.css" rel="stylesheet" />
<script src="/_layouts/15/cropper/jquery-cropper.js"></script>

<div class="form-ui ui blue segment">
    <span class="header">Параметры</span>
    <div class="form-row flex">
        <div class="form-item">
            <span class="title-ui">X</span>
            <asp:TextBox ID="_posX" CssClass="form-input" runat="server" style="width: 50px;"></asp:TextBox>
        </div>  
        <div class="form-item">
            <span class="title-ui">Y</span>
            <asp:TextBox ID="_posY" CssClass="form-input" runat="server" style="width: 50px;"></asp:TextBox>
        </div> 
        <div class="form-item">
            <span class="title-ui">Width</span>
            <asp:TextBox ID="_width" CssClass="form-input" runat="server" style="width: 50px;"></asp:TextBox>
        </div>
        <div class="form-item">
            <span class="title-ui">Height</span>
            <asp:TextBox ID="_height" CssClass="form-input" runat="server" style="width: 50px;"></asp:TextBox>
        </div> 
        <div class="form-item">
            <span class="title-ui">Rotate</span>
            <asp:TextBox ID="_rotate" CssClass="form-input" runat="server" style="width: 50px;"></asp:TextBox>
        </div> 
        <div class="form-item">
            <span class="title-ui">ScaleX</span>
            <asp:TextBox ID="_scaleX" CssClass="form-input" runat="server" style="width: 50px;"></asp:TextBox>
        </div> 
        <div class="form-item">
            <span class="title-ui">ScaleY</span>
            <asp:TextBox ID="_scaleY" CssClass="form-input" runat="server" style="width: 50px;"></asp:TextBox>
        </div> 
        <div class="form-item">  
            <span class="title-ui">Соотношение сторон</span>
            <asp:RadioButtonList CssClass="aspect-ratio" ID="_aspectRatio" runat="server" RepeatDirection="Horizontal">
                <asp:ListItem Value="1" Selected="True">1:1</asp:ListItem>
                <asp:ListItem Value="1.7777777777777777">16:9</asp:ListItem>
                <asp:ListItem Value="1.3333333333333333">4:3</asp:ListItem>
                <asp:ListItem Value="0.6666666666666666">2:3</asp:ListItem>
                <asp:ListItem Value="NaN">Произвольный</asp:ListItem>
            </asp:RadioButtonList>
        </div>         
    </div> 
    <div class="form-row flex">
        <div class="form-item">  
            <input type="file" id="_inputImage" name="file" class="form-file-upload" accept=".jpg,.jpeg,.png,.gif,.bmp,.tiff">
        </div>
        <div class="form-item">  
            <button class="action-btn" type="button" data-method="zoom" data-option="0.1" title="Увеличить">
                <i class="fa-solid fa-magnifying-glass-plus"></i>
            </button>
        </div> 
        <div class="form-item">  
            <button class="action-btn" type="button" data-method="zoom" data-option="-0.1" title="Уменьшить">
                <i class="fa-solid fa-magnifying-glass-minus"></i>
            </button>
        </div>
        <div class="form-item">  
            <button class="action-btn" type="button" data-method="move" data-option="-10" data-second-option="0" title="Подвинуть влево">
                <i class="fa-solid fa-arrow-left"></i>
            </button>
        </div> 
        <div class="form-item">  
            <button class="action-btn" type="button" data-method="move" data-option="10" data-second-option="0" title="Подвинуть вправо">
                <i class="fa-solid fa-arrow-right"></i>
            </button>
        </div>
        <div class="form-item">  
            <button class="action-btn" type="button" data-method="move" data-option="0" data-second-option="-10" title="Подвинуть вверх">
                <i class="fa-solid fa-arrow-up"></i>
            </button>
        </div> 
        <div class="form-item">  
            <button class="action-btn" type="button" data-method="move" data-option="0" data-second-option="10" title="Подвинуть вниз">
                <i class="fa-solid fa-arrow-down"></i>
            </button>
        </div>
        <div class="form-item">  
            <button class="action-btn" type="button" data-method="rotate" data-option="-45" title="Вращать влево">
                <i class="fa-solid fa-rotate-left"></i>
            </button>
        </div>
        <div class="form-item">  
            <button class="action-btn" type="button" data-method="rotate" data-option="45" title="Вращать вправо">
                <i class="fa-solid fa-rotate-right"></i>
            </button>
        </div>
        <div class="form-item">  
            <button class="action-btn" type="button" data-method="scaleX" data-option="-1" title="Отразить по горизонтали">
                <i class="fa-solid fa-arrows-left-right"></i>
            </button>
        </div>
        <div class="form-item">  
            <button class="action-btn" type="button" data-method="scaleY" data-option="-1" title="Отразить по вертикали">
                <i class="fa-solid fa-arrows-up-down"></i>
            </button>
        </div>
        <div class="form-item">  
            <button class="action-btn" type="button" data-method="reset" title="Сброс">
                <i class="fa-solid fa-rotate"></i>
            </button>
        </div>
        <div class="form-item">  
            <button class="action-btn" type="button" data-method="getCroppedCanvas" data-option="{ 'maxWidth': 4096, 'maxHeight': 4096 }" title="Подтвердить">
                <i class="fa-solid fa-check"></i>
            </button>
        </div>
        <div class="form-item">              
            <a class="action-btn" id="download" href="/" title="Сохранить" style="display:none;" ><i class="fa-solid fa-download"></i></a>
        </div> 
    </div>
</div>

<div>
    <asp:Image ID="_image" runat="server" />
</div>

Добавляем код в code behind

private SPSite oSite;
private SPWeb oWeb;
private string imgURL;

protected void Page_Load(object sender, EventArgs e)
{
    oSite = SPContext.Current.Site;
    oWeb = SPContext.Current.Web;
    _image.CssClass = "cropper";

    if (Page.Request.Params["source"] != null)
    {
        imgURL = Page.Request.Params["source"];                
        _image.ImageUrl = imgURL;
    }
}

На страницу добавляем JS

<script language="javascript" type="text/javascript">
    $(document).ready(function() {  
        
        $("div[class='ms-cui-topBar2']").hide();
        $("table[class='ms-webpartPage-root']").css("border-spacing", "0");
        $(".ms-webpartPage-root").css("border-spacing", "0");

        var URL = window.URL || window.webkitURL;   
        
        var $image = $('.cropper');
        var $download = $('#download');
        var $inputImage = $("input[id$='_inputImage']");
        $image.hide();
        
        setTimeout(InitCropper, 100);
        
        function InitCropper()
        {
            $image.show();
        
            var $dataX = $("input[id$='posX']");
            $dataX.val($image.width());         
            var $dataY = $("input[id$='posY']");
            $dataY.val($image.height());    
            var $dataHeight = $("input[id$='height']");
            $dataHeight.val($image.height());
            var $dataWidth = $("input[id$='width']");
            $dataWidth.val($image.width());
            var $dataRotate = $("input[id$='rotate']");
            $dataRotate.val("0");
            var $dataScaleX = $("input[id$='scaleX']");
            $dataScaleX.val("0");
            var $dataScaleY = $("input[id$='scaleY']");
            $dataScaleY.val("0");
            var options = {
                aspectRatio: 1 / 1,
                preview: '.img-preview',                
                
                //data:{ //define cropbox size
                  //width: 200,
                  //height:  90,
                //},
                crop: function (e) {
                    $dataX.val(Math.round(e.detail.x));
                    $dataY.val(Math.round(e.detail.y));
                    $dataHeight.val(Math.round(e.detail.height));
                    $dataWidth.val(Math.round(e.detail.width));
                    //$dataHeight.val(200);
                    //$dataWidth.val(200);
                    $dataRotate.val(e.detail.rotate);
                    $dataScaleX.val(e.detail.scaleX);
                    $dataScaleY.val(e.detail.scaleY);
                }
            };
            var $aspectRatio = $('.aspect-ratio');
            
            var $actionBtn = $('.action-btn');
            
            var originalImageURL = $image.attr('src');
            var uploadedImageName = 'cropped.jpg';
            var uploadedImageType = 'image/jpeg';
            var uploadedImageURL;
            /*
            $image.cropper({
                //aspectRatio: 16 / 9,
                crop: function(e) {
                    $dataX.val(Math.round(e.detail.x));
                    $dataY.val(Math.round(e.detail.y));
                    $dataHeight.val(Math.round(e.detail.height));
                    $dataWidth.val(Math.round(e.detail.width));
                    $dataRotate.val(e.detail.rotate);
                    $dataScaleX.val(e.detail.scaleX);
                    $dataScaleY.val(e.detail.scaleY);           
                }
            });
            */
            // Get the Cropper.js instance after initialized
            var cropper = $image.data('cropper');
            
            // Cropper
            $image.on({
                ready: function (e) {
                    //console.log(e.type);
                },
                cropstart: function (e) {
                    //console.log(e.type, e.detail.action);
                },
                cropmove: function (e) {
                    //console.log(e.type, e.detail.action);
                },
                cropend: function (e) {
                    //console.log(e.type, e.detail.action);
                },
                crop: function (e) {
                    //console.log(e.type);
                },
                zoom: function (e) {
                    //console.log(e.type, e.detail.ratio);
                }
            }).cropper(options);
            
            // Соотношение сторон
            $aspectRatio.on('change', 'input', function () {
                var $this = $(this);
                //var name = $this.attr('name');
                //var type = $this.prop('type');
                var cropBoxData;
                var canvasData;
                
                if (!$image.data('cropper')) {
                    return;
                }
                /*
                if (type === 'checkbox') {
                    options[name] = $this.prop('checked');
                    cropBoxData = $image.cropper('getCropBoxData');
                    canvasData = $image.cropper('getCanvasData');
                    
                    options.ready = function () {
                        $image.cropper('setCropBoxData', cropBoxData);
                        $image.cropper('setCanvasData', canvasData);
                    };
                } 
                else */
                //if (type === 'radio') 
                //{
                options["aspectRatio"] = $this.val();
                //}
                
                $image.cropper('destroy').cropper(options);
            });
            
            // Download
            if (typeof $download[0].download === 'undefined') {
                $download.addClass('disabled');
            }
            
            // Кнопки
            $actionBtn.click(function() {
                var $this = $(this);
                var data = $this.data();
                var cropper = $image.data('cropper');
                var cropped;
                var $target;
                var result;
                
                if ($this.prop('disabled') || $this.hasClass('disabled')) {
                    return;
                }
                
                if (cropper && data.method) {
                    data = $.extend({}, data); // Clone a new one
                
                    if (typeof data.target !== 'undefined') {
                        $target = $(data.target);
                
                        if (typeof data.option === 'undefined') {
                            try 
                            {
                                data.option = JSON.parse($target.val());
                            } catch (e) 
                            {
                                console.log(e.message);
                            }
                        }
                    }
                
                    cropped = cropper.cropped;
                
                    switch (data.method) 
                    {
                        case 'rotate':
                            if (cropped && options.viewMode > 0) 
                            {
                                $image.cropper('clear');
                            }
                
                        break;
                
                        case 'getCroppedCanvas':
                            if (uploadedImageType === 'image/jpeg') 
                            {
                                if (!data.option) 
                                {
                                    data.option = {};
                                }
                
                                data.option.fillColor = '#fff';
                            }
                
                        break;
                    }
                
                    result = $image.cropper(data.method, data.option, data.secondOption);
                
                    switch (data.method) {
                        case 'rotate':
                        if (cropped && options.viewMode > 0) 
                        {
                            $image.cropper('crop');
                        }
                
                        break;
                
                        case 'scaleX':
                        case 'scaleY':
                        $(this).data('option', -data.option);
                         break;
                
                        case 'getCroppedCanvas':
                        if (result) 
                        {
                            //console.log(result.toDataURL(uploadedImageType));
                            //window.open(result.toDataURL(uploadedImageType), '_blank').focus();
                            $download.attr('href', result.toDataURL(uploadedImageType));
                            $download.css("display", "block")
                            // Bootstrap's Modal
                            //$('#getCroppedCanvasModal').modal().find('.modal-body').html(result);
                
                            if (!$download.hasClass('disabled')) 
                            {
                                download.download = uploadedImageName;
                                $download.attr('href', result.toDataURL(uploadedImageType));
                            }
                            
                        }
                
                        break;
                
                        case 'destroy':
                            if (uploadedImageURL) 
                            {
                                URL.revokeObjectURL(uploadedImageURL);
                                uploadedImageURL = '';
                                $image.attr('src', originalImageURL);
                            }
                
                        break;
                    }
                
                    if ($.isPlainObject(result) && $target) 
                    {
                        try 
                        {
                            $target.val(JSON.stringify(result));
                        } 
                        catch (e) 
                        {
                            console.log(e.message);
                        }
                    }
                }
            });
            
            // Keyboard
            $(document.body).on('keydown', function (e) {
                if (e.target !== this || !$image.data('cropper') || this.scrollTop > 300) 
                {
                    return;
                }
            
                switch (e.which) {
                    case 37:
                        e.preventDefault();
                        $image.cropper('move', -1, 0);
                        break;
                
                    case 38:
                        e.preventDefault();
                        $image.cropper('move', 0, -1);
                        break;
                
                    case 39:
                        e.preventDefault();
                        $image.cropper('move', 1, 0);
                        break;
                
                    case 40:
                        e.preventDefault();
                        $image.cropper('move', 0, 1);
                        break;
                }
            });
            
            // Импорт изображения           
            if (URL) 
            {
                $inputImage.change(function () {
                    var files = this.files;
                    var file;
                
                    if (!$image.data('cropper')) 
                    {
                        return;
                    }
                
                    if (files && files.length) 
                    {
                        file = files[0];
                
                        if (/^image\/\w+$/.test(file.type)) 
                        {
                            uploadedImageName = file.name;
                            uploadedImageType = file.type;
                
                            if (uploadedImageURL) 
                            {
                                URL.revokeObjectURL(uploadedImageURL);
                            }
                
                            uploadedImageURL = URL.createObjectURL(file);
                            $image.cropper('destroy').attr('src', uploadedImageURL).cropper(options);
                            $inputImage.val('');
                            $download.css("display", "none")
                        } 
                        else 
                        {
                            window.alert('Пожалуйста, выберете файл с изображением');
                        }
                    }
                });
            } 
            else 
            {
                $inputImage.prop('disabled', true).parent().addClass('disabled');
            }
        }           
            
    });
</script>

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *