问题
I am trying to clip images into shapes and then draw them on canvas. I am curious how would I clip an image to return it as an oval shape. Would I use something like arc()
or bezierCurves()
?
回答1:
I believe the most convenient way would be to set the border radius.
#hey{
background:red;
color:white;
padding:5px;
border-radius:5px;
}
<div id="hey">hey</div>
If you want to do it with javascript, you should use:
document.getElementById("hey").style.borderRadius="5px";
This also works with images.
回答2:
You will need to create a oval clipping path. You can approximate an oval with four Bezier curves. Assuming that you want the oval to fit inside a rectangle, the curve end points can be the mid points of the sides of the rectangle and the curve control points can be half way between the mid points of the sides of the rectangle and the corners of the rectangle.
For example, you could use the following HTML code for a canvas element...
<canvas id="myCanvas" width="300" height="250"></canvas>
with the following JavaScript code to draw an image using a roughly oval clipping path...
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var r = { x: 50, y: 50, w: 200, h: 150 };
var imag = new Image();
imag.src = "images/koala.png";
imag.addEventListener("load", function () {
context.save();
context.beginPath();
context.moveTo(r.x + r.w, r.y + 0.5 * r.h);
context.bezierCurveTo(r.x + r.w, r.y + 0.25 * r.h, r.x + 0.75 * r.w, r.y, r.x + 0.5 * r.w, r.y);
context.bezierCurveTo(r.x + 0.25 * r.w, r.y, r.x, r.y + 0.25 * r.h, r.x, r.y + 0.5 * r.h);
context.bezierCurveTo(r.x, r.y + 0.75 * r.h, r.x + 0.25 * r.w, r.y + r.h, r.x + 0.5 * r.w, r.y + r.h);
context.bezierCurveTo(r.x + 0.75 * r.w, r.y + r.h, r.x + r.w, r.y + 0.75 * r.h, r.x + r.w, r.y + 0.5 * r.h);
context.closePath();
context.clip();
context.drawImage(imag, r.x, r.y, r.w, r.h);
context.restore();
});
An alternative solution for creating the oval path, would be to use arc() method to create a circle path and then use scale() method to transform the circle path into an oval path.
回答3:
You can draw an oval by scaling a circle (circle == arc) like this:
// Make an oval that's twice as tall as its width
// and draw it at the center of the canvas
var scaleX=1;
var scaleY=2;
var radius=canvas.width;
ctx.scale(scaleX,scaleY);
ctx.arc(canvas.width/scaleX/2,canvas.height/scaleY/2,radius,0,Math.PI*2);
ctx.fill();
Then you can use compositing to draw the image so it only appears inside the oval.
This is done with context.globalCompositeOperation='source-atop'
which causes new pixels to appear only if they overlap existing opaque pixels:
Toss in a little bit of math ratios and you can even get the oval to display the maximum amount of image...
Example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/kidwallpaper.jpg";
function start(){
// resize the canvas to equal the image size
var iw=img.width;
var ih=img.height;
cw=canvas.width=iw;
ch=canvas.height=ih;
// calculate the scaling needed to max the display of the image
// inside the oval
if(iw>ih){
var scaleX=iw/ih
var scaleY=1;
var r=ih/2;
}else{
var scaleX=1;
var scaleY=ih/iw;
var r=iw/2;
}
// scale so the circle (arc) becomes an oval
ctx.scale(scaleX,scaleY);
ctx.arc(cw/scaleX/2,ch/scaleY/2,r,0,Math.PI*2);
ctx.fill();
// undo the scaling
ctx.scale(1/scaleX,1/scaleY);
// draw the image centered inside the oval using compositing
ctx.globalCompositeOperation='source-atop';
ctx.drawImage(img,cw/2-img.width/2,ch/2-img.height/2);
ctx.globalCompositeOperation='source-atop';
}
body{ background-color: black; }
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=300 height=300></canvas>
来源:https://stackoverflow.com/questions/33898822/clip-an-image-to-form-an-oval-centered-image