如果你遵循正确的复合操作步骤,你可以这样做:
const canvas = document.getElementById( 'canvas' );
const ctx = canvas.getContext( '2d' );
const image = new Image;
image.addEventListener( 'load', draw );
// I just googled something
image.src = 'https://d2qp0siotla746.cloudfront.net/img/use-cases/profile-picture/template_3.jpg';
function draw(){
const w = image.naturalWidth;
const h = image.naturalHeight;
canvas.width = w;
canvas.height = h;
// First, draw the blurred version
ctx.save();
ctx.filter = 'blur(100px)';
ctx.drawImage( image, 0, 0 );
ctx.restore();
// Cut out the part you want unblurred.
// You could also do this by drawing a mask image
// But because this is Stack Overflow,
// I'm gonna keep it simple
ctx.save();
ctx.globalCompositeOperation = 'destination-out';
ctx.beginPath();
ctx.arc( w/2, h/2, Math.min(w,h) / 3, 0, Math.PI * 2 );
ctx.fill();
ctx.restore();
// Draw in a non-blurred image in the
// remaining unused pixels
// ("Draw the new content BEHIND the existing content")
ctx.save();
ctx.globalCompositeOperation = 'destination-over';
ctx.drawImage( image, 0, 0 );
ctx.restore();
}
canvas { max-width: 100%; }
<canvas id="canvas"></canvas>
这里有一个小动画来展示步骤:
const canvas = document.getElementById( 'canvas' );
const ctx = canvas.getContext( '2d' );
const image = new Image;
const message = document.getElementById( 'message' );
const speedInput = document.getElementById( 'speed' );
let d = speedInput.valueAsNumber;
speedInput.addEventListener( 'input', () => { d = speedInput.valueAsNumber; });
image.addEventListener( 'load', draw );
// I just googled something
image.src = 'https://d2qp0siotla746.cloudfront.net/img/use-cases/profile-picture/template_3.jpg';
async function delay(d, m){
message.textContent = m;
return new Promise(r => setTimeout(r,d));
}
async function draw(){
const w = image.naturalWidth;
const h = image.naturalHeight;
canvas.width = w;
canvas.height = h;
await delay( d, 'Resetting' );
ctx.save();
ctx.filter = 'blur(100px)';
ctx.drawImage( image, 0, 0 );
ctx.restore();
await delay( d, 'Added blur' );
ctx.save();
ctx.globalCompositeOperation = 'destination-out';
ctx.beginPath();
ctx.arc( w/2, h/2, Math.min(w,h) / 3, 0, Math.PI * 2 );
ctx.fill();
ctx.restore();
await delay( d, 'Remove shape' );
ctx.save();
ctx.globalCompositeOperation = 'destination-over';
ctx.drawImage( image, 0, 0 );
ctx.restore();
await delay( d, 'Add unblurred image' );
return draw();
}
canvas { max-width: 100%; }
<p id="message">Loading image...</p>
<canvas id="canvas"></canvas>
<input type="range" min="100" max="10000" value="1000" id="speed" />