将图像裁剪为不规则形状并拉伸 [英] Crop the image in irregular shape and stretch it

查看:25
本文介绍了将图像裁剪为不规则形状并拉伸的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我找到了描述我的问题的图片:

用户可以在画布上选择四个点来裁剪图像的一部分,然后拉伸它.

如何在 HTML5 中做到这一点?drawImage 函数(据我所知)仅适用于矩形(采用 x、y、宽度和高度值),因此我不能使用不规则形状.该解决方案必须适用于每个现代浏览器,所以我不想要基于 webgl 或其他东西的东西.

更多信息:这将是用于编辑图片的应用程序.我想让用户剪切更大图片的一部分并对其进行编辑.它与Paint类似,因此需要画布来编辑像素.

解决方案

所以这里有一个绝招:你可以使用 context2d 的常规 drawImage 在三角形内绘制纹理.
约束是纹理坐标必须是轴对齐的.

要绘制带纹理的三角形,您必须:
• 自己计算绘制图像所需的变换.
• 剪辑到三角形,因为 drawImage 会绘制一个四边形.
• 具有正确变换的drawImage.

所以我们的想法是将你的四边形分成两个三角形,然后渲染它们.

但是还有一个技巧:在绘制右下三角形时,纹理读取应该从纹理的右下部分开始,然后向上和向左移动.这不能在 Firefox 中完成,它只接受 drawImage 的正参数.所以我计算了第一个点与其他两个点的镜像",我可以再次在常规方向上绘制——剪裁将确保只绘制正确的部分——.

小提琴在这里:

I found images that depict what is my problem:

User will able to choose four points on canvas to crop the part of image and than stretch it.

How to do that in HTML5? drawImage function (as I know) works only with rectangles (takes x, y, width and height values) so I can't use irregular shape. The solution have to work in every modern browser, so I don't want things based on webgl or something.

EDIT: More info: this will be app for editing pictures. I want to let user cut some part of bigger picture and edit that. It will be similar to Paint, so canvas is required to edit pixels.

解决方案

So here's a killing trick : You can use the regular drawImage of the context2d to draw a texture inside a triangle.
The constraint is that the texture coordinates must be axis-aligned.

To draw a textured triangle you have to :
• Compute by yourself the transform required to draw the image.
• Clip to a triangle, since drawImage would draw a quad.
• drawImage with the right transform.

So the idea is to split your quad into two triangles, and render both.

But there's one more trick : when drawing the lower-right triangle, texture reading should start from the lower-right part of the texture, then move up and left. This can't be done in Firefox, which accepts only positive arguments to drawImage. So i compute the 'mirror' of the first point vs the two others, and i can draw in the regular direction again -the clipping will ensure only right part is drawn-.

fiddle is here :

http://jsfiddle.net/gamealchemist/zch3gdrx/

function rasterizeTriangle(v1, v2, v3, mirror) {
    var fv1 = {
        x: 0,
        y: 0,
        u: 0,
        v: 0
    };
    fv1.x = v1.x;
    fv1.y = v1.y;
    fv1.u = v1.u;
    fv1.v = v1.v;
    ctx.save();
    // Clip to draw only the triangle
    ctx.beginPath();
    ctx.moveTo(v1.x, v1.y);
    ctx.lineTo(v2.x, v2.y);
    ctx.lineTo(v3.x, v3.y);
    ctx.clip();
    // compute mirror point and flip texture coordinates for lower-right triangle
    if (mirror) {
        fv1.x = fv1.x + (v3.x - v1.x) + (v2.x - v1.x);
        fv1.y = fv1.y + (v3.y - v1.y) + (v2.y - v1.y);
        fv1.u = v3.u;
        fv1.v = v2.v;
    }
    // 
    var angleX = Math.atan2(v2.y - fv1.y, v2.x - fv1.x);
    var angleY = Math.atan2(v3.y - fv1.y, v3.x - fv1.x);
    var scaleX = lengthP(fv1, v2);
    var scaleY = lengthP(fv1, v3);
    var cos = Math.cos,
        sin = Math.sin;
    // ----------------------------------------
    //     Transforms
    // ----------------------------------------
    // projection matrix (world relative to center => screen)
    var transfMatrix = [];
    transfMatrix[0] = cos(angleX) * scaleX;
    transfMatrix[1] = sin(angleX) * scaleX;
    transfMatrix[2] = cos(angleY) * scaleY;
    transfMatrix[3] = sin(angleY) * scaleY;
    transfMatrix[4] = fv1.x;
    transfMatrix[5] = fv1.y;
    ctx.setTransform.apply(ctx, transfMatrix);
    // !! draw !!
    ctx.drawImage(bunny, fv1.u, fv1.v, v2.u - fv1.u, v3.v - fv1.v,
    0, 0, 1, 1);
    //
    ctx.restore();
};

Edit : i added the relevant comment of @szym , with his example picture :

This only sort of looks right. If there are any straight lines in the original image you will see that each triangle is warped differently (2 different affine transforms rather than a perspective transform).

这篇关于将图像裁剪为不规则形状并拉伸的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆