簡體   English   中英

如何調整大小然后使用 canvas 裁剪圖像

[英]How to resize then crop an image with canvas

我已經知道怎么做

-> 調整圖像大小:

var image = document.getElementById('myImage'),
    canvas = document.createElement('canvas'),
    ctx = canvas.getContext('2d');
ctx.drawImage(image,0,0,400,300);

-> 或裁剪圖像:

var image = document.getElementById('myImage'),
    canvas = document.createElement('canvas'),
    ctx = canvas.getContext('2d');
ctx.drawImage(image,50,50,image.width,image.height,0,0,50,50);

但我不知道如何調整大小然后裁剪圖像。 我怎么能這樣做? 謝謝你。

文檔中,這些是drawImage的參數:

 drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh); 

在此處輸入圖片說明

因此,要從源圖像中裁剪外部 10 個像素(假設它是100 * 50 ),然后將其縮放到160*60

ctx.drawImage(image,
    10, 10,   // Start at 10 pixels from the left and the top of the image (crop),
    80, 30,   // "Get" a `80 * 30` (w * h) area from the source image (crop),
    0, 0,     // Place the result at 0, 0 in the canvas,
    160, 60); // With as width / height: 160 * 60 (scale)

例子:

 var image = new Image(), canvas = document.getElementById('canvas'), ctx = canvas.getContext('2d'); image.src = 'https://i.stack.imgur.com/I4jXc.png'; image.onload = function(){ ctx.drawImage(image, 70, 20, // Start at 70/20 pixels from the left and the top of the image (crop), 50, 50, // "Get" a `50 * 50` (w * h) area from the source image (crop), 0, 0, // Place the result at 0, 0 in the canvas, 100, 100); // With as width / height: 100 * 100 (scale) }
 Image: <br/> <img src="https://i.stack.imgur.com/I4jXc.png" /><br/> Canvas: <br/> <canvas id="canvas" width="275px" height="95px"></canvas>

在畫布上繪制之前,使用 canvas.width 和 canvas.height 指定最終畫布大小,否則最終將始終為 300x150

我以本教程為例http://tympanus.net/codrops/2014/10/30/resizing-cropping-images-canvas/並在 vanilla js 中做了同樣的事情。 它可能需要一些重構,但它正在工作(至少在我的 Windows labtop 上使用 chrome)

一個 html 文件:

<!DOCTYPE html>
<html lang="en">
 <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
    * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
    /* styles for resize container and image */
    .resize-container {
        position: relative;
        display: inline-block;
        cursor: move;
        margin: 0 auto;
        top: 0;
        left: 0;
    }

    .resize-container img {
        display: block
    }

    .resize-container:hover img,
    .resize-container:active img {
        outline: 2px dashed rgba(222,60,80,.9);
    }
    /* styles for resize handles */
    .resize-handle-ne,
    .resize-handle-se,
    .resize-handle-nw,
    .resize-handle-sw {
        position: absolute;
        display: block;
        width: 10px;
        height: 10px;
        background: rgba(222, 60, 80, .9);
        z-index: 999;
    }

    .resize-handle-nw {
        top: -5px;
        left: -5px;
        cursor: nw-resize;
    }

    .resize-handle-sw {
        bottom: -5px;
        left: -5px;
        cursor: sw-resize;
    }

    .resize-handle-ne {
        top: -5px;
        right: -5px;
        cursor: ne-resize;
    }

    .resize-handle-se {
        bottom: -5px;
        right: -5px;
        cursor: se-resize;
    }
    .overlay {
        position: absolute;
        left: 50%;
        top: 50%;
        margin-left: -100px;
        margin-top: -100px;
        z-index: 999;
        width: 200px;
        height: 200px;
        border: solid 2px rgba(222,60,80,.9);
        box-sizing: content-box;
        pointer-events: none;
    }

    .overlay:after,
    .overlay:before {
        content: '';
        position: absolute;
        display: block;
        width: 204px;
        height: 40px;
        border-left: dashed 2px rgba(222,60,80,.9);
        border-right: dashed 2px rgba(222,60,80,.9);
    }

    .overlay:before {
        top: 0;
        margin-left: -2px;
        margin-top: -40px;
    }

    .overlay:after {
        bottom: 0;
        margin-left: -2px;
        margin-bottom: -40px;
    }

    .overlay-inner:after,
    .overlay-inner:before {
        content: '';
        position: absolute;
        display: block;
        width: 40px;
        height: 204px;
        border-top: dashed 2px rgba(222,60,80,.9);
        border-bottom: dashed 2px rgba(222,60,80,.9);
    }

    .overlay-inner:before {
        left: 0;
        margin-left: -40px;
        margin-top: -2px;
    }

    .overlay-inner:after {
        right: 0;
        margin-right: -40px;
        margin-top: -2px;
    }

    .btn-crop {
        position: absolute;
        vertical-align: bottom;
        right: 5px;
        bottom: 5px;
        padding: 6px 10px;
        z-index: 999;
        background-color: rgb(222,60,80);
        border: none;
        border-radius: 5px;
        color: #FFF;
    }

    #result {
        position: absolute;
        top: 0;
        left: 0;
        width: 100vw;
        height: 150vh;
        z-index: -1;
        display: flex;
        align-items: flex-end;
    }
  </style>
 </head>
  <body>
 <div id="resize-container" class="resize-container">
    <span class="resize-handle resize-handle-nw"></span>
    <span class="resize-handle resize-handle-ne"></span>
    <span class="resize-handle resize-handle-sw"></span>
    <span class="resize-handle resize-handle-se"></span>
    <img id="img" class="resize-image" src="image.png" alt="Image" />
</div>
<div id="overlay" class="overlay">
    <div class="overlay-inner">
    </div>
</div>
<button id="js-crop" class="btn-crop">Crop</button>
<div id="result"></div>

<script>
    const resizeableImage = image_target => {
        // defining the variables 
        let constrain = false

        const overlay = document.getElementById('overlay')
        const cropBtn = document.getElementById('js-crop')
        const container = document.getElementById('resize-container')
        const orig_src = new Image()
        const event_state = {}
        const min_width = 60
        const min_height = 60
        const max_width = 800
        const max_height = 900
        
        const resize_canvas = document.createElement('canvas')

        const resizeImage = (width, height) => {
            resize_canvas.width = width 
            resize_canvas.height = height 
            resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height)
            image_target.src = resize_canvas.toDataURL("image/png")
        }

        // the resizing function is where most of the action happens. This function is contansly invoked 
        // while the user is dragging one of the resize handles. Every time this function is called we
        // work out the new with and height by taking the current position of the mouse relative to the
        // initial position of the corner we are dragging
        const resizing = e => {
            let width, height, left, top 

            const rec = container.getBoundingClientRect()
            const offset = {
                top: rec.top + window.scrollY,
                left: rec.left + window.scrollX
            }
            const mouse = {
                x: (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + window.screenLeft,
                y: (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + window.screenTop
            }

            const eTargetClass = event_state.evnt.target.classList[1]
            // if statements for being able to resize from each corner
            if (eTargetClass === 'resize-handle-se') { // south-east (bottom-right)
                width = mouse.x - event_state.container_left
                height = mouse.y  - event_state.container_top
                left = event_state.container_left
                top = event_state.container_top
            } else if (eTargetClass === 'resize-handle-sw') { // south-west (bottom-left)
                width = event_state.container_width - (mouse.x - event_state.container_left)
                height = mouse.y  - event_state.container_top
                left = mouse.x
                top = event_state.container_top
            } else if (eTargetClass === 'resize-handle-ne') { // north-east (top-right)
                width = mouse.x - event_state.container_left
                height = event_state.container_height - (mouse.y - event_state.container_top)
                left = event_state.container_left
                top = mouse.y

                if(constrain || e.shiftKey){
                    top = mouse.y - ((width / orig_src.width * orig_src.height) - height)
                }
            } else if (eTargetClass === 'resize-handle-nw') { // north-west (top-left)
                width = event_state.container_width - (mouse.x - event_state.container_left)
                height = event_state.container_height - (mouse.y - event_state.container_top)
                left = mouse.x
                top = mouse.y

                if(constrain || e.shiftKey){
                    top = mouse.y - ((width / orig_src.width * orig_src.height) - height)
                }
            }


            if (constrain || e.shiftKey) {
                height = width / orig_src.width * orig_src.height 
            }

            if (width > min_width && height > min_height && width < max_width && height < max_height) {
                container.style.top = `${top}px`
                container.style.left = `${left}px`
                resizeImage(width, height)
            }
        }

        // before we start tracking the mouse position we want to take
        // a snapshot of the container dimensions and other key data
        // points. We store these in a variable named event_state and
        // use them later as a point of reference while resizing to
        // work out the change in height and width
        const saveEventState = e => {
            event_state.container_width = container.getBoundingClientRect().width 
            event_state.container_height = container.getBoundingClientRect().height 
            event_state.container_left = container.offsetLeft
            event_state.container_top = container.offsetTop 
            // mouse coordinates
            event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + window.screenLeft,
            event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + window.screenTop,

            event_state.evnt = e
        }

        // this two functions do very little other that tell the 
        // browser to start paying attention to where the mouse
        // is moving and when to stop paying attention
        const startResize = e => {
            e.preventDefault()
            e.stopPropagation()
            saveEventState(e)
            
            document.addEventListener('mousemove', resizing)
            document.addEventListener('mouseup', endResize)
        }

        const endResize = e => {
            e.preventDefault()
            //  The touchend event fires when one or more touch points are
            // removed from the touch surface.
            document.removeEventListener('mousemove', resizing)
            document.removeEventListener('touchend', resizing)
            document.removeEventListener('mouseup', endResize)
            document.removeEventListener('touchmove', endResize)
        }

        // in this function we need to work out the new position of the top left edge of the 
        // container. This will be equal to the current position of the mouse, offset by the
        // distance the mouse was from the top left corner when we started dragging the image
        const moving = e => {
            const mouse = {
                x: (e.clientX || e.pageX) + window.screenLeft,
                y: (e.clientY || e.pageY) + window.screenTop
            }

            container.style.left = `${mouse.x - (event_state.mouse_y - event_state.container_top)}px`
            container.style.top = `${mouse.y - (event_state.mouse_y - event_state.container_top)}px`
        }

        // function for moving the image around
        const startMoving = e => {
            e.preventDefault()
            e.stopPropagation()
            saveEventState(e)

            document.addEventListener('mousemove', moving)
            document.addEventListener('mouseup', endMoving)
        }

        const endMoving = e => {
            e.preventDefault()

            document.removeEventListener('mouseup', endMoving)
            document.removeEventListener('mousemove', moving)
        }

        const crop = e => {
            const left = overlay.offsetLeft - container.offsetLeft 
            const top = overlay.offsetTop - container.offsetTop 
            const width = overlay.getBoundingClientRect().width
            const height = overlay.getBoundingClientRect().height

            const crop_canvas = document.createElement('canvas')
            crop_canvas.width = width 
            crop_canvas.height = height 

            crop_canvas.getContext('2d').drawImage(image_target, left, top, width, height, 0, 0, width, height)

            const croppedImage = document.createElement('img')
            croppedImage.src = crop_canvas.toDataURL("image/png")
            document.querySelector('#result').appendChild(croppedImage)
        }

        // this function is called immediately and makes a copy of the
        // original image used for resizing
        const init = () => {
            // create a new image with a copy of the original src
            // When resizing, we will always use this original copy
            // as the base
            orig_src.src = image_target.src

            // add events
            container.addEventListener('mousedown', startResize)
            image_target.addEventListener('mousedown', startMoving)
            cropBtn.addEventListener('click', crop)
        }

        init()
    }

    // initializing the canvas and the target image
    const image = document.getElementById('img')
    resizeableImage(image)
</script>

執行以下操作以刪除圖像中的空白。

var canvas = document.getElementById("canvas");
var context = canvas.getContext('2d');

var imgWidth = canvas.width;
var imgHeight = canvas.height;

var imgData = context.getImageData(0, 0, imgWidth, imgHeight).data;

// get the corners of the content (not the spaces)
var cropTop = scanY(true);
var cropBottom = scanY(false);
var cropLeft = scanX(true);
var cropRight = scanX(false);

var cropXDiff = cropRight - cropLeft;
var cropYDiff = cropBottom - cropTop;

// get the content that doesn't contain outer spaces
var data = this.context!.getImageData(cropLeft, cropTop, cropXDiff, cropYDiff);

// set again width, height and image data
canvas.width = data.width;
canvas.height = data.height;
context.putImageData(data);

這是 scanX 和 scanY 函數

scanX = function (fromLeft) {
    var offset = fromLeft? 1 : -1;

    // loop through each column
    for(var x = fromLeft ? 0 : imgWidth - 1; fromLeft ? (x < imgWidth) : (x > -1); x += offset) {

        // loop through each row
        for(var y = 0; y < imgHeight; y++) {
            var rgb = getRBG(x, y);
            if (!isWhite(rgb)) {
                if (fromLeft) {
                    return x;
                } else {
                    return Math.min(x + 1, imgWidth);
                }
            }      
        }
    }
    return null; // all image is white
};

  scanY = function (fromTop) {
    var offset = fromTop ? 1 : -1;

    // loop through each row
    for(var y = fromTop ? 0 : imgHeight - 1; fromTop ? (y < imgHeight) : (y > -1); y += offset) {

        // loop through each column
        for(var x = 0; x < imgWidth; x++) {
            var rgb = getRBG(x, y);
            if (!isWhite(rgb)) {
                if (fromTop) {
                    return y;
                } else {
                    return Math.min(y + 1, imgHeight);
                }
            }
        }
    }
    return null; // all image is white
 }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM