【问题标题】:Crop Canvas / Export html5 canvas with certain width and height裁剪画布/导出具有特定宽度和高度的 html5 画布
【发布时间】:2012-10-15 22:26:48
【问题描述】:

有数百个教程,介绍如何在画布上通过 drawImage() 裁剪图像。

context.drawImage(imageObj, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight);

但是,我有一个可以填充用户浏览器的画布。通过将画布导出为图像,我只想从 (0|0) 导出 640px*480px 的区域。

问题:我如何告诉 javascript 只使用 640*480 的画布用于 toDataURL()?

这是我目前所拥有的:

$("#submitGraphic").click( function(){
    var canvas = document.getElementsByTagName("canvas");
    // canvas context
    var context = canvas[0].getContext("2d");
    // get the current ImageData for the canvas
    var data = context.getImageData(0, 0, canvas[0].width, canvas[0].height);
    // store the current globalCompositeOperation
    var compositeOperation = context.globalCompositeOperation;
    // set to draw behind current content
    context.globalCompositeOperation = "destination-over";
    //set background color
    context.fillStyle = "#FFFFFF";
    // draw background/rectangle on entire canvas
    context.fillRect(0,0,canvas[0].width,canvas[0].height);

    // not working, seems to clear the canvas? browser hangs?
    // seems that I can click a white image in the background
    /*canvas[0].width = 640;
    canvas[0].height = 480;*/

    // not working either
    /*canvas[0].style.width  = '640px';
    canvas[0].style.height = '480px';*/

    // not working at all
    /*context.canvas.width = 640;
    context.canvas.height = 480;*/

    // write on screen
    var img = canvas[0].toDataURL("image/png");
    document.write('<a href="'+img+'"><img src="'+img+'"/></a>');
})

PS:我不想调整大小或缩放,只是剪裁/裁剪到固定窗口。 Here 我读到您只指定 canvas.width 和 canvas.height - 但这会清除画布。

【问题讨论】:

    标签: javascript image html canvas crop


    【解决方案1】:

    最好的方法是创建一个临时画布以从当前画布上绘制。用户永远不会看到这个临时画布。然后你只需要在临时画布上使用toDataUrl()

    Live Demo

    $("#submitGraphic").click( function(){
        var canvas = document.getElementsByTagName("canvas");
        // canvas context
        var context = canvas[0].getContext("2d");
        // get the current ImageData for the canvas
        var data = context.getImageData(0, 0, canvas[0].width, canvas[0].height);
        // store the current globalCompositeOperation
        var compositeOperation = context.globalCompositeOperation;
        // set to draw behind current content
        context.globalCompositeOperation = "destination-over";
        //set background color
        context.fillStyle = "#FFFFFF";
        // draw background/rectangle on entire canvas
        context.fillRect(0,0,canvas[0].width,canvas[0].height);
    
        var tempCanvas = document.createElement("canvas"),
            tCtx = tempCanvas.getContext("2d");
    
        tempCanvas.width = 640;
        tempCanvas.height = 480;
    
        tCtx.drawImage(canvas[0],0,0);
    
        // write on screen
        var img = tempCanvas.toDataURL("image/png");
        document.write('<a href="'+img+'"><img src="'+img+'"/></a>');
    })​
    

    【讨论】:

    • 太棒了,效果很好! / 唯一让我恼火的是,当图像已经出现时,Firefox 会指示加载页面(标签显示旋转圆圈)。单击 ESC 在 url 中显示 wyciwyg:// !? ...“所见即所得是用于表示 document.write 结果页面的内部 URI 方案”/但无论如何,很高兴你给了我一个可行的解决方案!
    【解决方案2】:

    我创建了一个简单的通用函数,它通过返回一个带有裁剪区域的新画布来进行裁剪。虽然它没有“就地”进行裁剪,但它很简单。 记得在调用后切换到新的上下文。

    const cropCanvas = (sourceCanvas,left,top,width,height) => {
        let destCanvas = document.createElement('canvas');
        destCanvas.width = width;
        destCanvas.height = height;
        destCanvas.getContext("2d").drawImage(
            sourceCanvas,
            left,top,width,height,  // source rect with content to crop
            0,0,width,height);      // newCanvas, same size as source rect
        return destCanvas;
    }
    

    例如...

        let myCanvas = document.createElement('canvas');
        myCanvas.width = 200;
        myCanvas.height = 200;
        let myContext = myCanvas.getContext("2d");
        // draw stuff...
        myCanvas = cropCanvas(myCanvas,50,50,100,100);
        myContext = myCanvas.getContext("2d"); 
        // now using the cropped 100x100 canvas
    

    【讨论】:

      【解决方案3】:

      制作第二个屏幕外画布,将图像从第一个画布复制到第二个画布(使用第一个画布作为图像对象),然后导出第二个画布。

      【讨论】:

        【解决方案4】:

        纯html5画布裁剪:

        $('document').ready( function(){
        const divOffset = 1
        var x1,x2,y1,y2, xDif, yDif = 0;
        var isSelection, 
            isBottomRight, 
            isTopRight, 
            isTopLeft, 
            isBottomLeft = false
        
        var r = document.getElementById('source').getBoundingClientRect();
        var pos = [0, 0];
        pos[0] = r.left; 
        pos[1] = r.top; //got position coordinates of canvas
        
        var sel = document.getElementById('sel')
        var canvasSource = document.getElementById("source");
        var ctxSource = canvasSource.getContext("2d"); 
        
        var img = new Image()
        img.src = "http://bohdaq.name/assets/localImage.jpg"
        img.onload = function(){
          ctxSource.drawImage(img, 0, 0)
        }
        
        $( "#source" ).mousedown(function(event) {
           isSelection = true
        
           x1 = event.pageX - pos[0]
           y1 = event.pageY - pos[1]
        
           sel.style.setProperty('display', 'block')
        
           sel.style.setProperty('left', event.pageX + "px")
           sel.style.setProperty('top', event.pageY + "px")
        
           sel.style.setProperty('width', '0px')
           sel.style.setProperty('height', '0px')
        });
        
        $( "#source" ).mouseup(function(event) {
           isSelection = false
           if(isBottomRight){
             x2 = event.pageX - pos[0]
             y2 = event.pageY - pos[1]
        
             xDif = x2-x1
             yDif = y2-y1 
           } else if (isBottomLeft){
             y2 = event.pageY - pos[1]
             yDif = y2 - y1 
        
             xDif = x1 - x2
             x1 = x1 - xDif
        
           } else if(isTopRight){
             x2 = event.pageX - pos[0]
             xDif = x2 - x1 
             yDif = y1 - y2
             y1 = y1 - yDif         
           } else if (isTopLeft){
             xDif = x1 - x2
             x1 = x1 - xDif
             yDif = y1 - y2
             y1 = y1 - yDif         
           }
           sel.style.setProperty('display', 'none')
           crop(x1, y1, xDif, yDif)
        });
        
        $('#source').mousemove(function(event){
          if(isSelection){
            x2 = event.pageX - pos[0]
            y2 = event.pageY - pos[1]
            if(x2>x1 && y2>y1){ //moving right bottom selection
              isBottomRight = true
              isBottomLeft = false
              isTopLeft = false
              isTopRight = false
        
              xDif = x2 - x1
              yDif = y2 - y1 
        
              sel.style.setProperty('width', xDif + 'px')
              sel.style.setProperty('height', yDif + 'px')
            } else if(x2<x1 && y2>y1){ //moving left bottom selection
              isBottomLeft = true
              isTopLeft = false
              isTopRight = false
              isBottomRight = false
        
              xDif = x1 - x2
              yDif = y2 - y1 
        
              sel.style.setProperty('left', x2 + 'px')
              sel.style.setProperty('width', xDif + 'px')
              sel.style.setProperty('height', yDif + 'px')
        
            } else if(x2>x1 && y2<y1){
              isTopRight = true
              isTopLeft = false
              isBottomLeft = false
              isBottomRight = false
        
              xDif = y1 - y2
              yDif = x2 - x1 
        
              sel.style.setProperty('top', y2 + 'px')
              sel.style.setProperty('width', yDif + 'px')
              sel.style.setProperty('height', xDif + 'px')
            } else if (x2<x1 && y2<y1){
              isTopLeft = true
              isTopRight = false
              isBottomLeft = false
              isBottomRight = false
        
              yDif = y1 - y2 
              xDif = x1 - x2
        
              sel.style.setProperty('left', x2 + pos[0] + divOffset + 'px')
              sel.style.setProperty('top', y2 + pos[1] + divOffset + 'px')
              sel.style.setProperty('width', xDif  + 'px')
              sel.style.setProperty('height', yDif  + 'px')
            }
         }
        })
        
        function crop(x, y, xDif, yDif){
            canvasSource.width = xDif
            canvasSource.height = yDif
            ctxSource.drawImage(img, x, y, xDif, yDif, 0, 0, xDif, yDif);
        }
        
        })
        

        【讨论】:

          【解决方案5】:

          基于@GarySkiba 的回答:

          // crop canvas function
          const cropCanvas = (
            canvas: any,
            x: number,
            y: number,
            width: number,
            height: number
          ) => {
            // create a temp canvas
            const newCanvas = document.createElement('canvas');
            // set its dimensions
            newCanvas.width = width;
            newCanvas.height = height;
            // draw the canvas in the new resized temp canvas 
            newCanvas
              .getContext('2d')!
              .drawImage(canvas, x, y, width, height, 0, 0, width, height);
            return newCanvas
          };
          

          像这样使用它:

          // get canvas from somewhere
          const canvas = ....;
          // crop the left top 50x50 rect
          const newCanvas = cropCanvas(canvas, 0, 0, 50, 50 );
          // get the relative image
          newCanvas.toDataURL('image/png')
          
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-05-01
            • 2015-01-25
            • 2011-04-13
            • 1970-01-01
            • 2023-03-07
            • 1970-01-01
            相关资源
            最近更新 更多