【问题标题】:Why does Canvas's putImageData not work when I specify target location?为什么指定目标位置时 Canvas 的 putImageData 不起作用?
【发布时间】:2021-12-02 01:58:57
【问题描述】:

在尝试查找 Canvas 上下文的 putImageData() 方法的文档时,我发现了如下内容:

context.putImageData(imgData,x,y,dirtyX,dirtyY,dirtyWidth,dirtyHeight);

(来自http://www.w3schools.com/tags/canvas_putimagedata.asp

根据我阅读的文档,x 和 y 是 图像的索引,而dirtyX 和dirtyY 指定目标画布中绘制图像的坐标。然而,正如您从下面的示例(和 JSFiddle)中看到的那样,调用 putImageData(imgData,x,y) 有效,而 putImageData(imgData, 0, 0, locX, locY) 无效。我不知道为什么。

编辑:

我想我真正的问题是为什么图像的第一行是黑色的,并且只有 7 行,而不是 8 行。图像应该从画布的左上角开始。它们确实从左侧开始(并且有 8 列)。为什么他们不从顶部开始?

答案:那是由于yLoc为0时这一行除以0:

xoff = imgWidth / (yLoc/3);

JSFiddle:

http://jsfiddle.net/WZynM/

代码:

<html>
    <head>
        <title>Canvas tutorial</title>

        <script type="text/javascript">
            var canvas;
            var context; // The canvas's 2d context

            function setupCanvas()
            {
                canvas = document.getElementById('myCanvas');
                if (canvas.getContext)
                {
                    context = canvas.getContext('2d');
                    context.fillStyle = "black";    // this is default anyway
                    context.fillRect(0, 0, canvas.width, canvas.height);
                }
            }

            function init()
            {
                loadImages();
                startGating();
            }

            var images = new Array();
            var gatingTimer;
            var curIndex, imgWidth=0, imgHeight;

                // Load images
            function loadImages()
            {
                for (n = 1; n <= 16; n++)
                {
                    images[n] = new Image();
                    images[n].src = "qxsImages/frame" + n + ".png";
                //  document.body.appendChild(images[n]);

                    console.log("width = " + images[n].width + ", height = " + images[n].height);
                }

                curIndex = 1;
                imgWidth = images[1].width;
                imgHeight = images[1].height;
            }

            function redrawImages()
            {
                if (imgWidth == 0)
                    return;

                curIndex++;
                if (curIndex > 16)
                    curIndex = 1;

                    // To do later: use images[1].width and .height to layout based on image size
                for (var x=0; x<8; x++)
                {
                    for (var y=0; y<8; y++)
                    {
                        //if (x != 1)
                    //      context.drawImage(images[curIndex], x*150, y*100);
                        //  context.drawImage(images[curIndex], x*150, y*100, imgWidth/2, imgHeight/2); // scale
                    //  else
                            self.drawCustomImage(x*150, y*100);
                    }
                }
            }

            function drawCustomImage(xLoc, yLoc)
            {
                    // create a new pixel array
                imageData = context.createImageData(imgWidth, imgHeight);

                pos = 0; // index position into imagedata array
                xoff = imgWidth / (yLoc/3); // offsets to "center"
                yoff = imgHeight / 3;

                for (y = 0; y < imgHeight; y++) 
                {
                    for (x = 0; x < imgWidth; x++) 
                    {
                        // calculate sine based on distance
                        x2 = x - xoff;
                        y2 = y - yoff;
                        d = Math.sqrt(x2*x2 + y2*y2);
                        t = Math.sin(d/6.0);

                        // calculate RGB values based on sine
                        r = t * 200;
                        g = 125 + t * 80;
                        b = 235 + t * 20;

                        // set red, green, blue, and alpha:
                        imageData.data[pos++] = Math.max(0,Math.min(255, r));
                        imageData.data[pos++] = Math.max(0,Math.min(255, g));
                        imageData.data[pos++] = Math.max(0,Math.min(255, b));
                        imageData.data[pos++] = 255; // opaque alpha
                    }
                }

                    // copy the image data back onto the canvas
                context.putImageData(imageData, xLoc, yLoc);        // Works... kinda
            //  context.putImageData(imageData, 0, 0, xLoc, yLoc, imgWidth, imgHeight);  // Doesn't work. Why?
            }


            function startGating()
            {
                gatingTimer = setInterval(redrawImages, 1000/25); // start gating
            }

            function stopGating()
            {
                clearInterval(gatingTimer);
            }
        </script>

        <style type="text/css">
            canvas { border: 1px solid black; }
        </style>
    </head>

    <body onload="setupCanvas(); init();">
        <canvas id="myCanvas" width="1200" height="800"></canvas>
    </body>
</html>

http://jsfiddle.net/WZynM/

【问题讨论】:

  • 应该显示什么?在这里运行这个例子,我得到了一个黑色的背景,里面有一些蓝色的图像,里面有白色的圆圈。您能否发布具有预期结果(或接近结果)的图像?
  • 图片的第一行是黑色的,但里面应该有一些蓝/白图片。

标签: html canvas


【解决方案1】:

你只是把坐标倒了。

context.putImageData(imageData, xLoc, yLoc, 0, 0, imgWidth, imgHeight); 

Live Demo

xLocyLoc 是您放置它的位置,0,0,imgWidth,imgHeight 是您放置在画布上的数据。

Another example 显示此内容。

很多在线文档似乎有点矛盾,但对于七参数版本

putImageData(img, dx, dy, dirtyX, dirtyY, dirtyRectWidth, dirtyRectHeight)

dx 和 dy 是你的目的地,接下来的四个参数是脏 rect 参数,基本上控制 什么 你正在从源画布 绘制。我能找到的最详尽的描述之一是在 Simon Sarris 的《HTML5 Unleashed》(第 165 页)一书中。

【讨论】:

  • 谢谢。那么后续问题:为什么我的画布顶部有一排黑色?第一次调用 putImageData() 将 0,0 指定为 dx 和 dy 位置。所以最上面的行应该有蓝/白图像,但它是黑色的。 (您会注意到垂直方向只有 7 行,而应该是 8 行。)知道为什么吗?
  • @VernJensen 那是因为这条线 xoff = imgWidth / (yLoc / 3); 除以 0 会抛出整个顶行,幸运的是与 putImageData 无关。 jsfiddle.net/loktar/WZynM/5我改成xoff = imgWidth/3只是为了说明。
  • 谢谢!在看到你的帖子之前,我自己就发现了同样的事情。 ;-)
  • 作为拥有这本书的人:我可以确认你应该得到它并阅读它。
  • 哇,我正在阅读“要绘制的矩形的高度”,这意味着它将图像缩放到那个高度,这完全是不是 i> 它的作用。
【解决方案2】:

最近一直在使用它,我发现上面的 Loktar 遇到了一个非常重要的问题。基本上,这种方法的一些在线文档是不正确的,一个特别危险的例子是 W3Schools,很多人会转向参考。

他们的文档说明如下:

简介:

  • context.putImageData(imgData,x,y,dirtyX,dirtyY,dirtyWidth,dirtyHeight);

参数:

  • imgData:指定要放回画布上的 ImageData 对象
  • x :ImageData 对象左上角的 x 坐标(以像素为单位)[错误]
  • y : ImageData 对象左上角的 y 坐标(以像素为单位)[错误]
  • dirtyX:可选。在画布上放置图像的水平 (x) 值(以像素为单位)[错误]
  • dirtyY:可选。在画布上放置图像的垂直 (y) 值(以像素为单位)[错误]
  • dirtyWidth:可选。用于在画布上绘制图像的宽度
  • dirtyHeight:可选。用于在画布上绘制图像的高度

正如 Loktar 所述,正确的概要如下:

正确的概要:

  • context.putImageData(imgData, canvasX, canvasY, srcX ,srcY, srcWidth, srcHeight);

参数:

  • imgData:指定要放回画布上的 ImageData 对象(和以前一样);
  • canvasX : 绘制图像数据的 CANVAS 上位置的 x 坐标;
  • canvasY : 绘制 ImageData 的 CANVAS 上位置的 y 坐标;
  • srcX:可选。 ImageData 左上角的 x 坐标;
  • srcY:可选。 ImageData 左上角的 y 坐标;
  • srcWidth:可选。 ImageData 的宽度;
  • srcHeight:可选。 ImageData 的高度。

使用上面的正确的概要,就不会有上面遇到的问题了。

我将给 Loktar 一个重要的提示,以帮助 Loktar 最初发现这一点,但我认为提供扩展答案以防其他人遇到同样的问题是合适的。

【讨论】:

  • 谢谢大卫,非常清楚
猜你喜欢
  • 2017-06-08
  • 1970-01-01
  • 2023-03-19
  • 2013-06-29
  • 2021-10-21
  • 1970-01-01
  • 1970-01-01
  • 2022-09-23
  • 1970-01-01
相关资源
最近更新 更多