キャンバス上で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のみを指定していると読みましたが、これでキャンバスがクリアされます。
最良の方法は、現在のキャンバスから描画する一時的なキャンバスを作成することです。ユーザーには、この一時的なキャンバスは表示されません。次に、一時キャンバスで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>');
})
トリミングされた領域を持つ新しいキャンバスを返すことによってトリミングを行う単純な汎用関数を作成しました。 「インプレース」でトリミングを行うわけではありませんが、簡単です。 呼び出し後に新しいコンテキストに切り替えることを忘れないでください。
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
純粋な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);
}
})
2番目のオフスクリーンキャンバスを作成し、最初のキャンバスから2番目のキャンバスに画像をコピーして(最初のキャンバスを画像オブジェクトとして使用)、2番目のキャンバスをエクスポートします。
@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')