代码之家  ›  专栏  ›  技术社区  ›  user3334085

使用html5画布将图像剪辑为多边形的可重用函数

  •  4
  • user3334085  · 技术社区  · 11 年前

    我猜这篇文章的标题可能需要编辑,但目前我不知道问题在哪里。我在这里和其他地方读过类似问题的页面和答案。一个堆栈溢出的答案特别接近,但我不明白。

    我需要一个函数,在画布上以所需的坐标绘制多边形,并用从文件加载的一些背景图像填充它们(足够大,不需要平铺)。三角形可以做测试。显然,我应该使用drawImage和clip,为了给多边形一个边界,我可以重新绘制剪辑和笔划的相同路径。显然我应该遵守

    - define path
    - save
    - clip
    - drawImage
    - restore
    - stroke.
    

    也可以在某个地方阅读,只要加载一次图像就足够了。(如果uou想让我引用所有这些假设的来源,我会寻找我看到它们的地方。大多数都在Stack Overflow上)

    HTML为空

    <body onload = "main ();"></body>
    

    第一种方法,假装浏览器将等待图片加载:

    var ctx, img;
    var image_path = 'bg.jpg';
    
    function main () {
    
        var CANVAS_SIZE = 600;
        var view_field_cnv = document.createElement ('canvas');
        view_field_cnv.width  = CANVAS_SIZE;
        view_field_cnv.height = CANVAS_SIZE;
        view_field_cnv.style.border = "1px solid";
        document.body.appendChild (view_field_cnv);
        ctx = view_field_cnv.getContext ('2d');
    
        img = document.createElement ('img');
        img.src = image_path;
    
        place_triangle (0, 0);
        place_triangle (300, 300);
        place_triangle (500, 500);
        place_triangle (0, 0);
    
    }
    
    function place_triangle (x, y) {
    
        console.log (x, y);
    
        ctx.beginPath ();
        ctx.moveTo (x + 10, y);
        ctx.lineTo (x + 110, y);
        ctx.lineTo (x + 60, y + 40);
        ctx.closePath ();
    
        img = document.createElement ('img');
        img.src = image_path;
    
        ctx.save ();
        ctx.clip ();
        ctx.drawImage (img, x, y);
        ctx.restore ();
        ctx.stroke ();
    
    
    }
    

    这将绘制所有三个三角形,但没有剪裁图像。

    第二次尝试,在image.onload中使用drawImage:

    var ctx;
    var image_path = 'bg.jpg';
    
    function main () {
    
        var CANVAS_SIZE = 600;
        var view_field_cnv = document.createElement ('canvas');
        view_field_cnv.width  = CANVAS_SIZE;
        view_field_cnv.height = CANVAS_SIZE;
        view_field_cnv.style.border = "1px solid";
        document.body.appendChild (view_field_cnv);
        ctx = view_field_cnv.getContext ('2d');
    
        place_triangle (0, 0);
        place_triangle (300, 300);
        place_triangle (500, 500);
        place_triangle (0, 0);
    
    }
    
    function place_triangle (x, y) {
    
        console.log (x, y);
    
        var img;
    
        ctx.beginPath ();
        ctx.moveTo (x + 10, y);
        ctx.lineTo (x + 110, y);
        ctx.lineTo (x + 60, y + 40);
        ctx.closePath ();
    
        img = document.createElement ('img');
        img.src = image_path;
        img.onload = function () {
    
            ctx.save ();
            ctx.clip ();
            ctx.drawImage (img, x, y);
            ctx.restore ();
            ctx.stroke ();
        }
    
    }
    

    这张确实画出了裁剪的图像,但只有一个三角形,最后一个。仅仅注释保存和恢复并没有帮助。

    所以,我不理解加载图像、保存、恢复以及可能的一百万其他事情。虫子在哪里?

    2 回复  |  直到 11 年前
        1
  •  7
  •   markE    11 年前

    我看你已经了解了剪辑的基本知识:

    • 保存上下文,定义路径,剪辑,drawImage,恢复上下文。

    • 如果您希望笔划与剪切图像稍微重叠,可以在恢复后进行笔划。

    • 如果不希望笔划与剪裁图像重叠,可以在剪裁之前进行笔划。

    enter image description here

    下面是示例代码和演示: http://jsfiddle.net/m1erickson/p0fup425/

    <!doctype html>
    <html>
    <head>
    <link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
    <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
    <style>
        body{ background-color: ivory; }
        canvas{border:1px solid red;}
    </style>
    <script>
    $(function(){
    
        var canvas=document.getElementById("canvas");
        var ctx=canvas.getContext("2d");
    
        // image loader
        // put the paths to your images in imageURLs[]
        var imageURLs=[];  
        // push all your image urls!
        imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/multple/norwayFlag.jpg");
        imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/multple/swedishFlag.jpg");
    
        // the loaded images will be placed in images[]
        var imgs=[];
    
        var imagesOK=0;
        loadAllImages(start);
    
        function loadAllImages(callback){
            for (var i=0; i<imageURLs.length; i++) {
                var img = new Image();
                imgs.push(img);
                img.onload = function(){ 
                    imagesOK++; 
                    if (imagesOK>=imageURLs.length ) {
                        callback();
                    }
                };
                img.onerror=function(){alert("image load failed");} 
                img.crossOrigin="anonymous";
                img.src = imageURLs[i];
            }      
        }
    
        function start(){
    
            // the imgs[] array now holds fully loaded images
            // the imgs[] are in the same order as imageURLs[]
    
            // clip image#1
            clippingPath([10,70,50,10,90,70],imgs[0],10,10);
    
            // clip image#2
            clippingPath([10,170,50,110,90,170],imgs[1],10,110);
    
            // append the original images for demo purposes
            document.body.appendChild(imgs[0]);
            document.body.appendChild(imgs[1]);
    
        }
    
        function clippingPath(pathPoints,img,x,y){
    
            // save the unclipped context
            ctx.save();
    
            // define the path that will be clipped to
            ctx.beginPath();
            ctx.moveTo(pathPoints[0],pathPoints[1]);
            // this demo has a known number of polygon points
            // but include a loop of "lineTo's" if you have a variable number of points
            ctx.lineTo(pathPoints[2],pathPoints[3]);
            ctx.lineTo(pathPoints[4],pathPoints[5]);
            ctx.closePath();    
    
            // stroke the path
            // half of the stroke is outside the path
            // the outside part of the stroke will survive the clipping that follows
            ctx.lineWidth=2;
            ctx.stroke();
    
            // make the current path a clipping path
            ctx.clip();
    
            // draw the image which will be clipped except in the clipping path
            ctx.drawImage(img,x,y);
    
            // restore the unclipped context (==undo the clipping path)
            ctx.restore();
        }
    
    
    }); // end $(function(){});
    </script>
    </head>
    <body>
        <p>Images clipped inside triangular canvas paths</p>
        <canvas id="canvas" width=150 height=200></canvas>
        <p>Original Images</p>
    </body>
    </html>
    
        2
  •  0
  •   Jvo    5 年前

    @标记E

    示例中的图像已消失。 我从上面的截图中剪下它们,上传到我们自己的网站,并克隆/更新了fiddle: http://jsfiddle.net/6gawtudc/

    我无法评论先前的回答,因为缺乏信誉分数。 请有人更新答案或重新上传图片

    imageURLs.push("https://images.v3.webhome.nl/flags_for_polygon/norway.png");
    imageURLs.push("https://images.v3.webhome.nl/flags_for_polygon/sweden.png");