最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - HTML5 photoshop like polygonal lasso selection - Stack Overflow

programmeradmin0浏览0评论

Im looking to build a tool to cut out a portion of a photo by letting the user create a closed shape. The user should be able to start drawing lines. From point a to point b, to c, e, d, e, f .... to eventually point a again to close the shape.

I want to use the HTML5 canvas for this. I think this could be a good fit and I'm thinking about using something like flashcanvas as fallback for IE/older browsers?

Is there any tutorial/open source application that I could use to build this sort of thing? This is the first time I'm going to build an application using HTML5 canvas so are there any pitfalls I should worry about?

Im looking to build a tool to cut out a portion of a photo by letting the user create a closed shape. The user should be able to start drawing lines. From point a to point b, to c, e, d, e, f .... to eventually point a again to close the shape.

I want to use the HTML5 canvas for this. I think this could be a good fit and I'm thinking about using something like flashcanvas as fallback for IE/older browsers?

Is there any tutorial/open source application that I could use to build this sort of thing? This is the first time I'm going to build an application using HTML5 canvas so are there any pitfalls I should worry about?

Share Improve this question asked Apr 12, 2012 at 7:52 Stijn_dStijn_d 1,0889 silver badges20 bronze badges 1
  • I've been googling for tutorials I only find pencil-like drawing-stuff(not point to point). And existing projects? => in don't know if you already checked this but that pixlr-editor is a FLASH-application? i'm looking for an HTML5-canvas solution – Stijn_d Commented Apr 12, 2012 at 12:26
Add a ment  | 

2 Answers 2

Reset to default 4

I think this is advanced usage of canvas. You have to know the basics, how to draw, how to use layers, how to manipulate pixels. Just ask google for tutorials.

Assuming you know about the previous, I'll give it a try. I've never done that before but I have an idea :

You need 3 canvas :

  • the one containing your picture (size of your picture)
  • a layer where the user draw the selection shape (size of your picture, on top of the first canvas)
  • a result canvas, will contain your cropped picture (same size, this one doesn't need to be displayed)

When the user click on your picture : actually, he clicks on the layer, the layer is cleared and a new line begins.

When he clicks on it another time, the previous started line is drawn and another one begins, etc... You keep doing this until you click on a non-blank pixel (which means you close the shape).

If you want the user to preview the lines, you need another canvas ( explained here http://dev.opera./articles/view/html5-canvas-painting/#line )

When the shape is closed, the user has to click inside or outside the shape to determine which part he wants to select. You fill that part with a semi-transparent gray for example ( flood fill explained here http://www.williammalone./articles/html5-canvas-javascript-paint-bucket-tool/ )

Now the layer canvas contains a colored shape corresponding to the user selection.

Get the pixel data from your layer and read through the array, every time you find a non-blank pixel at index i, you copy this pixel from your main canvas to the result canvas :

/* First, get pixel data from your 3 canvas into 
 * layerPixData, resultPixData, picturePixData 
*/

// read the entire pixel array
for (var i = 0 ; i < layerPixData.length ; i+=4 ) {
    //if the pixel is not blank, ie. it is part of the selected shape
    if ( layerPixData[i] != 255 || layerPixData[i+1]  != 255 || layerPixData[i+2] != 255 ) {
        // copy the data of the picture to the result
        resultPixData[i] = picturePixData[i]; //red
        resultPixData[i+1] = picturePixData[i+1]; //green
        resultPixData[i+2] = picturePixData[i+2]; //blue
        resultPixData[i+3] = picturePixData[i+3]; //alpha

        // here you can put the pixels of your picture to white if you want

    }

}

If you don't know how pixel manipulation works, read this https://developer.mozilla/En/HTML/Canvas/Pixel_manipulation_with_canvas

Then, use putImageData to draw the pixels to your result canvas. Job done !

If you want to move lines of your selection, way to go : http://simonsarris./blog/225-canvas-selecting-resizing-shape

Here is how you should do that: The code at the following adds a canvas on top of your page and then by clicking and dragging on that the selection areas would be highlighted. What you need to do after that is to make a screenshot from the underlying page and also a mask layer out of the created image in your canvas and apply that to the screenshot, just like how it is shown in one other answers.

/* sample css code for the canvas
#overlay-canvas {
    position: absolute;
    top: 0;
    left: 0;
    background-color: transparent;
    opacity: 0.4;
    -moz-user-select: none;
    -khtml-user-select: none;
    -webkit-user-select: none;
    -o-user-select: none;
}
*/

function getHighIndex(selector) {
    if (!selector) { selector = "*" };

    var elements = document.querySelectorAll(selector) ||
                   oXmlDom.documentElement.selectNodes(selector);
    var ret = 0;

    for (var i = 0; i < elements.length; ++i) {
        if (deepCss(elements[i],"position") === "static")
            continue;

        var temp = deepCss(elements[i], "z-index");

        if (temp != "auto")
            temp = parseInt(temp, 10) || 0;
        else
            continue;

        if (temp > ret)
            ret = temp;
    }
    return ret;
}

maxZIndex = getHighIndex();

$.fn.extend({
    lasso: function () {
        return this
        .mousedown(function (e) {
            // left mouse down switches on "capturing mode"
            if (e.which === 1 && !$(this).is(".lassoRunning")) {
                var point = [e.offsetX, e.offsetY];
                $(this).addClass("lassoRunning");
                $(this).data("lassoPoints", [point]);
                $(this).trigger("lassoStart", [point]);
            }
        })
        .mouseup(function (e) {
            // left mouse up ends "capturing mode" + triggers "Done" event
            if (e.which === 1 && $(this).is(".lassoRunning")) {
                $(this).removeClass("lassoRunning");
                $(this).trigger("lassoDone", [$(this).data("lassoPoints")]);
            }
        })
        .mousemove(function (e) {
            // mouse move captures co-ordinates + triggers "Point" event
            if ($(this).is(".lassoRunning")) {
                var point = [e.offsetX, e.offsetY];
                $(this).data("lassoPoints").push(point);
                $(this).trigger("lassoPoint", [point]);
            }
        });
    }
});


function onLassoSelect() {
    // creating canvas for lasso selection
    var _canvas = document.createElement('canvas');
    _canvas.setAttribute("id", "overlay-canvas");
    _canvas.style.zIndex = ++maxZIndex;
    _canvas.width = document.width
    _canvas.height = document.height
    document.body.appendChild(_canvas);
    ctx = _canvas.getContext('2d'),
    ctx.strokeStyle = '#0000FF';
    ctx.lineWidth = 5;

    $(_canvas)
        .lasso()

        .on("lassoStart", function(e, lassoPoint) {
            console.log('lasso start');

            var pos = lassoPoint;
            ctx.beginPath();
            ctx.moveTo(pos[0], pos[1]);
            console.log(pos);
        })

        .on("lassoDone", function(e, lassoPoints) {
            console.log('lasso done');

            var pos = lassoPoints[0];
            ctx.lineTo(pos[0], pos[1]);
            ctx.fill();
            console.log(pos);
        })

        .bind("lassoPoint", function(e, lassoPoint) {
            var pos = lassoPoint;
            ctx.lineTo(pos[0], pos[1]);
            ctx.fill();
            console.log(pos);
        });
}
发布评论

评论列表(0)

  1. 暂无评论