web-dev-qa-db-ja.com

キャンバスを切り抜く/特定の幅と高さのhtml5キャンバスをエクスポートする

キャンバス上でdrawImage()を使用して画像を切り抜く方法については、何百ものチュートリアルがあります。

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

しかし、私はユーザーのブラウザを埋めるキャンバスを持っています。キャンバスを画像としてエクスポートすることにより、(0 | 0)から640px * 480pxの領域のみをエクスポートしたいと思います。

問題:toDataURL()にキャンバスの640 * 480のみを使用するようにjavascriptに指示するにはどうすればよいですか?

これが私がこれまでに持っているものです:

$("#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:サイズ変更や拡大縮小はしたくありません。固定ウィンドウに切り抜く/切り抜くだけです。 ここ canvas.widthとcanvas.heightのみを指定していると読みましたが、これでキャンバスがクリアされます。

11
Kai Noack

最良の方法は、現在のキャンバスから描画する一時的なキャンバスを作成することです。ユーザーには、この一時的なキャンバスは表示されません。次に、一時キャンバスで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);

    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>');
})​
23
Loktar

トリミングされた領域を持つ新しいキャンバスを返すことによってトリミングを行う単純な汎用関数を作成しました。 「インプレース」でトリミングを行うわけではありませんが、簡単です。 呼び出し後に新しいコンテキストに切り替えることを忘れないでください。

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
2
GrumpyGary

純粋な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);
}

})
1
bohdaq

2番目のオフスクリーンキャンバスを作成し、最初のキャンバスから2番目のキャンバスに画像をコピーして(最初のキャンバスを画像オブジェクトとして使用)、2番目のキャンバスをエクスポートします。

1
Louis Ricci

@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')

0
Davide Carpini