将图像绘制到画布会为绘制的每个新图像返回InvalidStateError,然后成功 [英] Drawing images to canvas returns InvalidStateError for every new image drawn, then succeeds
问题描述
我有一个类似网格的无序列表,可以旋转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:
- 创建一个图像宽度x 12宽,一个图像高度x 12高的画布。这是为了表示最终产品图像。
- 遍历列表项(图像),从项中提取图像src并将其绘制到自己的画布上,该画布是图像的大小。
- 旋转新的小画布,但它的图像已在网格上旋转。
- 将新的小画布绘制到最终结果画布上当前指针的x和y。
- 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.
- 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.
- Rotate the new small canvas however it's image has been rotated on the grid.
- 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屋!