【问题标题】:Save un-scaled canvas with image background after changes were applied应用更改后使用图像背景保存未缩放的画布
【发布时间】:2013-06-18 10:30:41
【问题描述】:

我遇到了一个大问题,我花了将近一个星期的时间才能让它工作,所以我非常感谢任何帮助 - 我正在尝试用 html5 创建一个简单的图像编辑器,所以我上传了一张图片,将其加载到画布中然后在上面画画-

我还希望能够放大和缩小-只是我不知道应该如何保存画布状态-对于绘制鼠标事件,我正在使用一个保存 canvas.toDataUrl 的数组,但是这个将只保存它在画布中可见的内容,只保存缩放图像的一部分,而不是整个 -

如果有人知道如何将画布连同其上的绘画一起取消缩放并将其保存在堆栈中,我可以从中检索它以用于其他绘画活动,我将不胜感激!谢谢

【问题讨论】:

  • 请提供更多信息 :) 您要更改图像本身的像素还是要在图像顶部应用注释(线条、文本等)?
  • 你好,我想画线,就像画笔一样,而且我正在应用扭曲(图像扭曲)。只是在放大画布并应用所有编辑器后,如果我想保存状态,那么它不会保存未缩放的最终图像,只有画布中当前可见的图像的一部分 - 因为图像正在获取大于画布的宽度和高度,并且使用 dataURL,只会得到可见的内容...感谢您的回答

标签: html image canvas editor


【解决方案1】:

保存状态

画布的save()restore() 与画布中的像素完全无关。 Save() 只保存当前画笔颜色、填充颜色、变换、缩放、旋转等 - 只保存参数值,不保存实际像素数据。

因此,restore() 只会将这些参数值恢复到以前的值。

canvas 元素是被动的,这意味着它只保存您在屏幕上看到的像素。它不会保留任何内容的备份,因此如果您更改其大小、重新调整浏览器窗口大小或在浏览器中打开导致其清除的对话框,您将需要自己更新画布。

这也适用于您更改参数值(例如比例)时。画布上的任何内容都不会更改设置新值。唯一发生的事情是您的 next 绘制将使用这些参数值进行绘制(换句话说:如果您应用旋转,则不会旋转,但您绘制的下一个将旋转)。

在现有图像上绘图

由于您需要维护内容,这也意味着您需要存储所绘制的图像以及所绘制的内容。

当您绘制例如线条时,您需要将每个笔划记录到数组中。当画布需要更新(即缩放)时,您首先以新的比例重绘原始图像,然后用线条遍历数组并重新渲染它们。

点、矩形、圆和你有什么都一样。

将画布视为您在其他地方存储的内容(图像对象、数组、对象)的快照。 Canvas 只是该数据的一个视口。

我建议这样存储:

var backgroundImage;  //reference to your uploaded image

var renderStack = []; //stores all drawing objects (see below)

//example generic object to hold strokes, shapes etc.
function renderObject() {
    this.type = 'stroke';  //or rectangle, or circle, or dot, ...
    this.x1;
    this.y1;
    this.x2;
    this.y2;
    this.radius;
    this.penWidth;
    this.penColor;
    this.fillColor;
    this.points = [];
    //...  extend as you need or use separate object for each type
}

然后当你画一个笔触(伪):

var currentRenderObject;

function mouseDown(e) {

    //get a new render object for new shape/line etc.
    currentRenderObject = new renderObject();

     //get type from your selected tool
    currentRenderObject.type = 'stroke'; //for example

    //do the normal draw operations, mouse position etc.
    x =..., y = ...
}

function mouseMove(e) {

    //get mouse positions, draw as normal
    x = ..., y = ...

    //store the points to the array, here:
    //we have a line or stroke, so we push the
    //values to ourpoint-array in the renderObject
    currentRenderObject.points.push(x);
    currentRenderObject.points.push(y);

}
function mouseUp(e) {

    //when paint is done, push the current renderObject
    //to our render stack
    renderStack.push(currentRenderObject);
}

现在你可以做一个重绘函数了:

function redraw() {

    clearCanvas();

    drawBackgroundImage();

    for(var i = 0, ro; ro = renderStack[i]; i++) {

        switch(ro.type) {
            case 'stroke':
                //... parse through point list
                break;
            case 'rectangle':
                //... draw rectangle
                break;
            ...
        }
    } 
}

function zoom(factor) {
    //set new zoom, position (scale/translate if you don't
    //want to do it manually). Remember that mouse coords need
    //to be recalculated as well to match the zoom factor.

    redraw();
}

//when canvas is scaled for some reason, or the window
canvas.onresize = windows.onresize = redraw;

这样做的好处是您也可以将渲染堆栈用作撤消/重做堆栈...

希望这有助于更好地了解画布的工作原理。

【讨论】:

  • 感谢您抽出宝贵的时间,它帮了很多忙,在阅读了您指出的转换数小时后,我将改进我实施的解决方案。
猜你喜欢
  • 2013-03-02
  • 2014-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-30
  • 1970-01-01
相关资源
最近更新 更多