Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   проблема с canvas image (https://javascript.ru/forum/misc/77491-problema-s-canvas-image.html)

korih 13.05.2019 14:34

проблема с canvas image
 
Добрый день уважаемые. столкнулся с проблемой на канвас. цель сделать простой кропер.
1)загруженное изображение скалируется под разрешение canvas (разрешение полотна 600х400)
2)на данное изображение накладывается черно-белый фильтр и блюр
3)создается второй слой этого же изображения, но уже цветно и обрезанное под нужное разрешение (разрешение можно динамически менять)
4) это слой можно передвигать по всему канвас-полотну и видеть какое изображение будет в результате на выходе
вот часть кода:
handleCanvas = () => {
        let { posX, posY, img} = this.state

        /*  
            img - загруженное изображение
            posX - координаты нового слоя с изобращением по Х
            posY - координаты нового слоя с изобращением по Y

        */

        let c=document.getElementById('canvas_t');
            if(c){
                //
                let MAX_WIDTH = 600;
                let MAX_HEIGHT = 400;
                let width = img.width;
                let height = img.height;

                if (width > height) {
                    if (width > MAX_WIDTH) {
                        height *= MAX_WIDTH / width;
                        width = MAX_WIDTH;
                    }
                } else {
                    if (height > MAX_HEIGHT) {
                        width *= MAX_HEIGHT / height;
                        height = MAX_HEIGHT;
                    }
                }
                //
                let ctx
                c.width = width
                c.height = height
                ctx = c.getContext('2d')
                ctx.clearRect(0, 0, 600, 400);
                ctx.filter = 'grayscale(100) blur(3px)'
                
                //рендерим фон изображения на полотне
                ctx.drawImage(img, 0, 0, width, height )
                

                //очищаем фильтр
                ctx.filter = 'grayscale(0) blur(0)'
                
                ctx.strokeRect(posX, posY, this.state.w, this.state.h)

                //рендерим новое изображение с позициями и указанным форматом
                ctx.drawImage(img , posX, posY,this.state.w,this.state.h, posX, posY, this.state.w,this.state.h)

                

                ctx.fillStyle = 'rgba(138, 196, 235, 0.7)'

                ctx.fillRect(posX + this.state.w - 5,posY + this.state.h - 5, 10,10)
            }      
    }


Суть проблемы:
редактируемый слой изображения не сходится с фоновым


Alexandroppolus 13.05.2019 14:59

Самый простой способ - сделать clip на основе текущей выбранной рамки кропа и зарядить ctx.drawImage(img, 0, 0, width, height ) повторно - отрисуется только тот квадратик, который в клипе.

Набросок:
...
ctx.save();
ctx.beginPath();
ctx.rect(posX, posY, this.state.w, this.state.h);
ctx.clip();
ctx.drawImage(img, 0, 0, width, height );
ctx.restore();
...


Плюс этого способа - не придется морочить голову сдвигами и размерами (если картинка не сжимается в размерах и рисуется как есть, то всё просто, иначе надо правильно подобрать параметры для самой полной версии drawImage, что слегонца геморно. Хотя, впрочем, спозиционировать установленную рамку на реальную картинку всё равно придется, так что можно и сразу это делать)

Alexandroppolus 13.05.2019 15:17

Кстати, картинка с размерами, к примеру, 600х500 неправильно посайзится в твоем кропе

Rise 13.05.2019 15:20

korih, когда рисуешь второе изображение, не учитываешь скалирование от первого.

Alexandroppolus 13.05.2019 15:31

навскидку, без clip

let MAX_WIDTH = 600;
let MAX_HEIGHT = 400;
let width = img.width;
let height = img.height;
let ratio = 1;

if (width > MAX_WIDTH || height > MAX_HEIGHT) {
    ratio = Math.max(width / MAX_WIDTH, height / MAX_HEIGHT);
    width = width / ratio;
    height = height / ratio;
}

......

//рендерим новое изображение с позициями и указанным форматом
ctx.drawImage(img, posX * ratio, posY * ratio, this.state.w * ratio, this.state.h * ratio, 
        posX, posY, this.state.w, this.state.h);

korih 13.05.2019 15:40

Alexandroppolus, спасибо тебе большое, очень помог

Malleys 13.05.2019 16:16

Alexandroppolus, korih,
const MAX_WIDTH = 600;
const MAX_HEIGHT = 400;
let width = img.width;
let height = img.height;
const ρ = 1 / Math.min(MAX_WIDTH / width, MAX_HEIGHT / height, 1);

width  /= ρ;
height /= ρ;

// ......

// дорисовываем новое изображение с позициями и указанным форматом
ctx.drawImage(img, posX * ρ, posY * ρ, this.state.w * ρ, this.state.h * ρ, 
        posX, posY, this.state.w, this.state.h);


Часовой пояс GMT +3, время: 06:15.