javascript 使用 HTML5 Canvas 为绘画应用程序创建逼真的铅笔工具

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10122553/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 08:45:27  来源:igfitidea点击:

Create a realistic pencil tool for a painting app with HTML5 Canvas

javascriptimage-processingcanvashtml5-canvas

提问by jazzytomato

First I want to say that I made a lot of research and tries myself without any success.

首先我想说我做了很多研究并尝试了自己,但没有成功。

I am working on a MSPaint-like application using Canvas, and I would like to create a pencil tool which looks realistic like handmade drawings... Here is an example in the link below with the default tool : http://www.onemotion.com/flash/sketch-paint/

我正在使用 Canvas 开发一个类似 MSPaint 的应用程序,我想创建一个看起来像手工绘图一样逼真的铅笔工具......这是下面链接中使用默认工具的示例: http://www.onemotion .com/flash/sketch-paint/

I tried to play with mousespeed and linewidth properties but it is not working well (the entire line enlarge and shrink as I move the mouse). I have no idea of an algorithm acting on pixel raw data.

我尝试使用 mousespeed 和 linewidth 属性,但效果不佳(当我移动鼠标时,整条线会放大和缩小)。我不知道对像素原始数据起作用的算法。

Do you know something existing or a suitable algorithm to apply ? Thank you very much for your help

你知道现有的东西或合适的算法吗?非常感谢您的帮助

EDIT

编辑

I decided to add the solution I've chosen because it seems to interest lot of people. So, the best thing I found so far is to draw an image onto the canvas, using the technique explained here : http://css.dzone.com/articles/sketching-html5-canvas-and. It works like a charm, the result is really convincing and this is quite easy to implement. Try it out here : http://tricedesigns.com/portfolio/sketch/brush.html#

我决定添加我选择的解决方案,因为它似乎引起了很多人的兴趣。所以,到目前为止我发现的最好的事情是使用这里解释的技术在画布上绘制图像:http: //css.dzone.com/articles/sketching-html5-canvas-and。它就像一个魅力,结果真的很有说服力,而且很容易实现。在这里试试:http: //tricedesigns.com/portfolio/sketch/brush.html#

回答by Loktar

You could try something like the following demo

您可以尝试以下演示

Live Demo

现场演示

Your most likely using moveToand lineToto create the paths, if you do it that way the properties will be shared for the path until you close the path. So everytime you change the thickness youd need to call closePathand then beginPathagain.

您最有可能使用moveTolineTo创建路径,如果您这样做,路径的属性将被共享,直到您关闭路径。因此,每次更改厚度时都需要调用closePath,然后beginPath再调用。

In my example I use Bresenham's line algorithmto plot the points. Basically onmousedown it starts painting. Then onmousemove it compares the current coordinates with the last coordinates and plots all of the points between. Its also using fillRectto paint. Based on how fast your moving the line will be thicker or thinner.

在我的示例中,我使用Bresenham 的线算法来绘制点。基本上onmousedown它开始绘画。然后 onmousemove 它将当前坐标与最后一个坐标进行比较并绘制它们之间的所有点。它也fillRect用于绘画。根据您移动线的速度将变粗或变细。

Heres the code for the drawing function

这是绘图功能的代码

var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    painting = false,
    lastX = 0,
    lastY = 0,
    lineThickness = 1;

canvas.width = canvas.height = 600;
ctx.fillRect(0, 0, 600, 600);

canvas.onmousedown = function(e) {
    painting = true;
    ctx.fillStyle = "#ffffff";
    lastX = e.pageX - this.offsetLeft;
    lastY = e.pageY - this.offsetTop;
};

canvas.onmouseup = function(e){
    painting = false;
}

canvas.onmousemove = function(e) {
    if (painting) {
        mouseX = e.pageX - this.offsetLeft;
        mouseY = e.pageY - this.offsetTop;

        // find all points between        
        var x1 = mouseX,
            x2 = lastX,
            y1 = mouseY,
            y2 = lastY;


        var steep = (Math.abs(y2 - y1) > Math.abs(x2 - x1));
        if (steep){
            var x = x1;
            x1 = y1;
            y1 = x;

            var y = y2;
            y2 = x2;
            x2 = y;
        }
        if (x1 > x2) {
            var x = x1;
            x1 = x2;
            x2 = x;

            var y = y1;
            y1 = y2;
            y2 = y;
        }

        var dx = x2 - x1,
            dy = Math.abs(y2 - y1),
            error = 0,
            de = dy / dx,
            yStep = -1,
            y = y1;

        if (y1 < y2) {
            yStep = 1;
        }

        lineThickness = 5 - Math.sqrt((x2 - x1) *(x2-x1) + (y2 - y1) * (y2-y1))/10;
        if(lineThickness < 1){
            lineThickness = 1;   
        }

        for (var x = x1; x < x2; x++) {
            if (steep) {
                ctx.fillRect(y, x, lineThickness , lineThickness );
            } else {
                ctx.fillRect(x, y, lineThickness , lineThickness );
            }

            error += de;
            if (error >= 0.5) {
                y += yStep;
                error -= 1.0;
            }
        }



        lastX = mouseX;
        lastY = mouseY;

    }
}

?

?