I'm trying to port one of my Processing projects (see Github page for the project) into vanilla Javascript but I'm having issues "transplanting" the data from one ImageData object into another ImageData object. I can fill an area of the canvas with a rectangle of color just fine, but for some reason the same does not work with images.
Here is the code I use to place an area of ImageData into another area of image data.
image(ix, iy, iw, ih, i) {
let xMin = ix;
let xMax = ix + iw;
let yMin = iy;
let yMax = iy + ih;
if (xMin < 0) xMin = 0;
if (xMax > this.w) xMax = this.w;
if (yMin < 0) yMin = 0;
if (yMax > this.h) yMax = this.h;
let data = this.buffer.data;
let im_data = i.buffer.data;
for (let x = xMin; x < xMax; x++) {
for (let y = yMin; y < yMax; y++) {
let i_x_off = x - ix;
let i_y_off = y - iy;
let ind = this.index(x, y);
let i_ind = this.index(i_x_off, i_y_off);
data[ind + 0] = im_data[i_ind + 0];
data[ind + 1] = im_data[i_ind + 1];
data[ind + 2] = im_data[i_ind + 2];
data[ind + 3] = im_data[i_ind + 3];
}
}
}
This is the function I am using to get the index into the ImageData from an x and y value
index(x, y) {
return y * (this.w * 4) + (x * 4);
}
And here is the function I have been using to put rectangles onto the canvas. Notice how similar it is to the image()
function
rect(rx, ry, rw, rh, c) {
let xMin = rx;
let xMax = rx + rw;
let yMin = ry;
let yMax = ry + rh;
if (xMin < 0) xMin = 0;
if (xMax > this.w) xMax = this.w;
if (yMin < 0) yMin = 0;
if (yMax > this.h) yMax = this.w;
let data = this.buffer.data;
for (let x = xMin; x < xMax; x++) {
for (let y = yMin; y < yMax; y++) {
let i = this.index(x, y);
data[i + 0] = c.r;
data[i + 1] = c.b;
data[i + 2] = c.g;
data[i + 3] = c.a;
}
}
}
There isn't really a way to show the problem without an image, so here is an image of the canvas with an image of the Godot logo. (This is the stretching I am talking about). Image of HTML5 canvas with Godot logo bug (Here is a reference for what the source image looks like). Godot logo from Twitter
In terms of the order the functions are executed in, see below.
const main = () => {
raw.flush(); // Setting all the "pixels" to RGBA 0, 0, 0, 0
raw.rect(10, 10, im.w, im.h, color());
raw.image(10, 10, im.w, im.h, im);
GLOBALCANVASCONTEXT.putImageData(raw.buffer, 0, 0); // The buffer is just another name for the result of ctx.createImageData(w, h)
window.requestAnimationFrame(main);
};