【问题标题】:How redraw on canvas resize without blurring?如何在不模糊的情况下在画布上重绘调整大小?
【发布时间】:2013-10-17 12:52:38
【问题描述】:

当画布元素被调整大小时(通过改变样式),我也想缩放画布的绘制图像。我不能只更改高度/宽度,因为这会导致画布自行清除,所以我这样做:

  1. 创建一个临时画布元素
  2. 将当前画布的图像绘制到该临时画布上
  3. 调整当前画布的大小
  4. 将临时画布的图像绘制回当前画布,但缩放到新大小

这会导致一些模糊 - 在多次调整大小后非常明显(例如:拖动以调整大小时)。我将如何在没有任何模糊的情况下做到这一点?

编辑:关闭图像平滑 (context.webkitImageSmoothingEnabled = false;) 并没有 解决问题,它只是让它重绘变得越来越锯齿,直到图像看起来不像多次调整大小后的原始版本。

在调整大小事件时调用:

    var tmpCanvas = null;       

    //Make a temporary canvas
    tmpCanvas = document.createElement( "canvas" );

    //Set its size to be equal
    tmpCanvas.height = originalCanvas.height;
    tmpCanvas.width = originalCanvas.width;

    //Draw our current canvas onto it
    tmpCanvas.getContext( "2d" ).drawImage( originalCanvas, 0, 0 );

    //Set new dimensions
    originalCanvas.width = originalCanvas.offsetWidth;
    originalCanvas.height = originalCanvas.offsetHeight;

    var originalContext = originalCanvas.getContext( "2d" );

    //Set background and colors
    originalContext.fillStyle = "#ffffff";
    originalContext.strokeStyle = "#000000";

    //Set paintbrush
    originalContext.lineWidth = 4;
    originalContext.lineCap = "round";

    //Fill background as white
    originalContext.fillRect( 0, 0, originalCanvas.width, originalCanvas.height );

    //We have a saved signature
    if ( SignatureCanvas.hasSignature === true )
    {
        //Draw it back but scaled (results in blurred image)
        originalContext.drawImage( tmpCanvas, 0, 0, tmpCanvas.width, tmpCanvas.height, 0, 0, originalCanvas.width, originalCanvas.height );

        /** 
         * This results in a blurred image as well
         //Draw it back but scaled
         originalContext.scale( originalCanvas.width / tmpCanvas.width, originalCanvas.height / tmpCanvas.height );
         originalContext.drawImage( tmpCanvas, 0, 0, tmpCanvas.width, tmpCanvas.height, 0, 0, tmpCanvas.width, tmpCanvas.height );
         */
    }

有没有办法获得笔触并“缩放”所有这些点并重绘?

【问题讨论】:

    标签: javascript css html canvas


    【解决方案1】:

    不是从原始画布中获取渲染图像,而是实际重绘图像。我的意思是执行与原始画布相同的逻辑,但涉及的点缩放到新的大小。

    如果可以,请考虑使用 SVG。它本质上可以很好地扩展。

    编辑:我想到的另一个选择是简单地使用一个巨大的画布开始。缩小尺寸看起来比放大尺寸更好,尤其是在启用平滑的情况下。

    【讨论】:

    • 我该怎么做?在第一个画布上绘制的图像是由用户完成的,所以我事先不知道它会是什么。有没有办法从绘制的画布中获取信息并缩放这些点并重新绘制它们?
    • 您需要存储用户执行的命令(我猜是在哪些点上绘制的)并以新的大小重放该逻辑。您需要某种矢量表示来干净地调整大小。否则,您只是在调整一个光栅图像的大小,而该图像的大小将看起来不合适。画布只是画布;它不像 SVG 那样存储层或组件。
    【解决方案2】:

    编辑二:最初的答案是无关紧要的,尽管我所做的评论是相关的,现在正在宣传它并将其编辑为一个答案......我给出的答案并不是那么好无论如何 **。

    当然如果你放大光栅图形,即从一个像素尺寸较小的图像,创建一个像素尺寸较高的图像,你会得到模糊的图像。通过放大,您可以制作高分辨率的低分辨率图片,但没有高分辨率细节

    除非您对光栅图像做出多项额外假设,例如您看到的唯一灰色位于图像边缘,否则绝对无法解决这种模糊,或者角点只能出现在明显的拐点处,其中切线之间的角度连接的曲线必须为 100 度或更小。本质上,您必须提供其他信息,以便您的更高分辨率图像可以“填充”细节。这与从栅格逆向工程 SVG 并没有太大的不同。

    因此,您似乎想要模拟缩放矢量图形,其中唯一的解决方案是保存命令、绘制 SVG 或像 Stuart Branham 建议的那样绘制到更大的画布。

    ** 我最初提出调用drawImage 会扭曲像素即使它没有被缩放,并且使用实际的像素数据会更好。 如果这是真的,我找不到证据,但这无关紧要,因为他希望放大他的图像,不模糊...这是不可能的,正如我刚才提到的.

    【讨论】:

    • 使用来自getImageData 的数据远非简单。返回的只是所有像素的红色、绿色、蓝色和 alpha 值的数组。我将如何扩展它?
    • 抱歉,我不清楚您是否在缩放。嗯,当然如果你缩放光栅图形,你会得到模糊的图像。除非您对您的光栅图像做出多个额外的假设,否则绝对没有办法解决这个问题(比如您看到的唯一灰色是在图像边缘,什么构成角落等)。您似乎想要模拟的是缩放 矢量图形,其中唯一的解决方案是保存命令或像 Stuart Branham 建议的那样使用 SVG。
    • 你错了,这是不可能的。只要您知道创建的路径,就可以缩放它们并在新大小的画布上重新绘制它们。这将产生一个不模糊的缩放副本。更多信息请看这里:stackoverflow.com/a/19284983/857025
    • 来自光栅图像!如果您正在使用创建的路径,那么您现在不是在使用光栅图像,是吗?
    • 光栅图像是像素,并且只有像素。如果您使用路径,则本质上是使用矢量图形。
    猜你喜欢
    • 2013-08-19
    • 2013-07-20
    • 2023-02-05
    • 2022-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-28
    • 1970-01-01
    相关资源
    最近更新 更多