将图像绘制到画布会为绘制的每个新图像返回InvalidStateError,然后成功 [英] Drawing images to canvas returns InvalidStateError for every new image drawn, then succeeds

查看:152
本文介绍了将图像绘制到画布会为绘制的每个新图像返回InvalidStateError,然后成功的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类似网格的无序列表,可以旋转144(90px x 90px)图像(12x12)。我的最终目标是拍摄144图像网格并将其保存为1张图像。

I have a grid-like unordered list with 144 (90px x 90px) images (12x12) that may be rotated. My end goal is to take the 144 image grid and save it as 1 image.

我当前的解决方案让我按照以下步骤操作:

My current solution has me following these steps:


  1. 创建一个图像宽度x 12宽,一个图像高度x 12高的画布。这是为了表示最终产品图像。

  2. 遍历列表项(图像),从项中提取图像src并将其绘制到自己的画布上,该画布是图像的大小。

  3. 旋转新的小画布,但它的图像已在网格上旋转。

  4. 将新的小画布绘制到最终结果画布上当前指针的x和y。

  1. Create a canvas that is one image width x 12 wide and one image height x 12 high. This is to represent the end product image.
  2. Loop through the list items(images), extracting the image src from the item and drawing it onto its own canvas that is the size of the image.
  3. Rotate the new small canvas however it's image has been rotated on the grid.
  4. Draw the new small canvas onto the end-result canvas at the x and y of the current pointer.



注意事项



当我遍历图像时,我会跟踪指针(我当前在画布上的位置)。我通过维护行和列号来完成此操作。它们代表我正在绘制的图像的当前行和列。我使用它们,乘以单个图像的宽度和高度,以获得画布上的精确x和y坐标以绘制下一个图像。

Things to note

As I loop through the images, I keep track of a pointer (where I am currently on the canvas). I do this by maintaining a row and a col number. They represent the current row and column of images I am drawing. I use them, multiplied by the width and height of a single image, to get the exact x and y coordinates on the canvas to draw the next image.

当我调用函数创建,绘制并生成画布的base64时,我收到以下错误消息:InvalidStateError:尝试使用不可用或不再可用的对象。。如果这个错误在100%的时间内发生,我会假设它,因为我正在绘制到画布的图像,要么尚未加载,要么根本没有加载,但是,我只收到一次此错误我加载的每个新图像。例如,如果我有一个144图像网格,即每次绘制72次的2个不同图像,我将收到两次InvalidStateError,然后第三次调用该函数,它将成功。

When I call the function to create, draw and generate the base64 of the canvas, I receive the following error message: "InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable.". If this error was occurring 100% of the time, I'd assume its because the image I'm drawing to the canvas, either isn't loaded yet or is not being loaded at all, but, I only receive this error once for every new image I load. For example, if I have a 144 image grid, that is 2 different images each drawn 72 times, I will receive InvalidStateError twice and then the third time I call the function, it will succeed.

请记住这只是用于测试保存图像的尖峰代码,我知道需要进行一些重构。

Please keep in mind this is simply spike code to test saving the image, I am aware some refactoring is required.

generateThumbnail: function(){
  var builder = this,
      canvas = document.createElement('canvas'),
      content,
      row = 0,
      col = 0;

  // width is single image width (90) x number of tiles wide (usually 12)
  canvas.width = 90 * builder.grid[0];
  // height is single image height (90) x number of tiles high (usually 12)
  canvas.height = 90 * builder.grid[1];
  // get 2d context of new canvas
  context = canvas.getContext("2d");

  // loop through all of the images on the grid
  $.each($(".pattern-grid li"), function(i, tile) {
    var $tile = $(tile),
        image = new Image(),
        src = $tile.find("img").attr("src"),
        width,
        height,
        buffer,
        bufferctx,
        x,
        y;

    // set crossOrigin of image to anonymous as these images are loaded via CORS
    image.crossOrigin = "Anonymous";

    // increase row number by 1 if it has reached the end of the row and its not the first image being drawn
    if(i % builder.grid[0] == 0 && i != 0){
      row++;
    }
    // Set Column to 0 if it is a new row, otherwise increase column by 1 (unless it is the first image being drawn)
    if(col == builder.grid[0]-1){
      col = 0;
    }else if(i != 0){
      col++;
    }

    // determine if there was no image drawn at this location
    if(src != undefined){
      image.src = src;
      // get the width and height the image, to be used for the small canvas and where to draw it
      width = image.width;
      height = image.height;
      // create a new buffer canvas to draw the image to, this will be used to apply any rotations that may exist
      buffer = document.createElement("canvas");
      //set width and height of the buffer to the current images width and height
      buffer.width = width;
      buffer.height = height;
      bufferctx = buffer.getContext("2d");
      //Determine x and y coordinates to draw the small canvas using row and column numbers
      x = col*width;
      y = row*height;
      //Save current state of buffer canvas
      bufferctx.save();
      //translate and then rotate the buffer canvas by the image's rotation
      bufferctx.translate(width/2, height/2);
      bufferctx.rotate($tile.find("img").data("rotation")*Math.PI/180);
      bufferctx.translate(width/2*-1, height/2*-1);
      //draw image to buffer canvas and restore its context
      bufferctx.drawImage(image, 0, 0);
      bufferctx.restore();
      //draw the buffer canvas to the main canvas at predetermined x and y
      context.drawImage(buffer, x, y, width, height);
    }
  });
  return canvas.toDataURL();
}


推荐答案

我能够使用@ abiessu的建议有一个onload,配有一个闭包来保存函数的状态。我的解决方案是:

I was able to use @abiessu's suggestion with an onload, paired with a closure to save state of the function. My solution, that works, is:

generateThumbnail: function(){
  var builder = this,
      canvas = document.createElement('canvas'),
      content,
      row = 0,
      col = 0;
  // width is single image width (90) x number of tiles wide (usually 12)
  canvas.width = 90 * builder.grid[0];
  // height is single image height (90) x number of tiles high (usually 12)
  canvas.height = 90 * builder.grid[1];
  context = canvas.getContext("2d");
  // loop through all of the images on the grid
  $.each($(".pattern-grid li"), function(i, tile) {
    var $tile = $(tile),
        image = new Image(),
        src = $tile.find("img").attr("src");
     // set crossOrigin of image to anonymous as these images are loaded via CORS
    image.crossOrigin = "Anonymous";
    // increase row number by 1 if it has reached the end of the row and its not the first image being drawn
    if(i % builder.grid[0] == 0 && i != 0){
      row++;
    }
    // increase row number by 1 if it has reached the end of the row and its not the first image being drawn
    if(col == builder.grid[0]-1){
      col = 0;
    }else if(i != 0){
      col++;
    }
    image.onload = function(row, col){
      return function(){
        // determine if there was no image drawn at this location
        if(src != undefined){
          var width = image.width,
              height = image.height,
              buffer = document.createElement("canvas"),
              bufferctx,
              x,
              y;
          buffer.width = width;
          buffer.height = height;
          bufferctx = buffer.getContext("2d");
          x = col*width;
          y = row*height;
          bufferctx.save();
          bufferctx.translate(width/2, height/2);
          bufferctx.rotate($tile.find("img").data("rotation")*Math.PI/180);
          bufferctx.translate(width/2*-1, height/2*-1);
          bufferctx.drawImage(image, 0, 0);
          bufferctx.restore();
          context.drawImage(buffer, x, y, width, height);
        }
      }
    }(row, col);
    image.src = $tile.find("img").attr("src");
  });
  window.canvas = canvas;
}

这篇关于将图像绘制到画布会为绘制的每个新图像返回InvalidStateError,然后成功的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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