2020-07-16 15:32:59 +08:00
|
|
|
/*
|
2023-02-05 04:15:01 +08:00
|
|
|
Utility to modify images with a canvas
|
2020-07-16 15:32:59 +08:00
|
|
|
*/
|
|
|
|
class CanvasFrame {
|
2023-06-01 04:07:08 +08:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {Number|HTMLCanvasElement|HTMLImageElement} [a] Image source
|
|
|
|
* @param {Number} [b]
|
|
|
|
*/
|
2023-02-05 04:15:01 +08:00
|
|
|
constructor(a, b) {
|
|
|
|
if (a && a.nodeName == 'CANVAS') {
|
|
|
|
if (a.getContext('2d')) {
|
|
|
|
this.canvas = a;
|
|
|
|
} else {
|
|
|
|
this.createCanvas(a.width, a.height)
|
|
|
|
this.loadFromImage(a)
|
|
|
|
}
|
2020-07-16 15:32:59 +08:00
|
|
|
|
2023-02-05 04:15:01 +08:00
|
|
|
} else if (a && a.nodeName == 'IMG') {
|
|
|
|
this.createCanvas(a.naturalWidth, a.naturalHeight)
|
|
|
|
this.loadFromImage(a)
|
2020-07-16 15:32:59 +08:00
|
|
|
|
2023-10-27 19:02:28 +08:00
|
|
|
} else {
|
|
|
|
this.createCanvas(a || 16, b || 16)
|
2023-02-05 04:15:01 +08:00
|
|
|
}
|
|
|
|
this.ctx = this.canvas.getContext('2d')
|
|
|
|
}
|
|
|
|
get width() {return this.canvas.width;}
|
|
|
|
get height() {return this.canvas.height;}
|
|
|
|
|
|
|
|
createCanvas(w, h) {
|
|
|
|
this.canvas = document.createElement('canvas');
|
|
|
|
this.canvas.width = w;
|
|
|
|
this.canvas.height = h;
|
|
|
|
this.ctx = this.canvas.getContext('2d')
|
|
|
|
}
|
|
|
|
async loadFromURL(url) {
|
|
|
|
let img = new Image()
|
|
|
|
img.src = url.replace(/#/g, '%23');
|
|
|
|
await new Promise((resolve, reject) => {
|
|
|
|
img.onload = () => {
|
|
|
|
this.loadFromImage(img);
|
|
|
|
resolve();
|
|
|
|
}
|
|
|
|
img.onerror = reject;
|
|
|
|
})
|
|
|
|
}
|
|
|
|
loadFromImage(img) {
|
|
|
|
if (img.naturalWidth) {
|
|
|
|
this.canvas.width = img.naturalWidth;
|
|
|
|
this.canvas.height = img.naturalHeight;
|
|
|
|
}
|
|
|
|
this.ctx.drawImage(img, 0, 0)
|
|
|
|
}
|
2023-05-28 21:13:00 +08:00
|
|
|
loadFromCanvas(canvas) {
|
|
|
|
this.canvas.width = canvas.width;
|
|
|
|
this.canvas.height = canvas.height;
|
|
|
|
this.ctx.drawImage(canvas, 0, 0)
|
2023-02-05 04:15:01 +08:00
|
|
|
}
|
|
|
|
autoCrop() {
|
|
|
|
// Based on code by remy, licensed under MIT
|
|
|
|
// https://gist.github.com/remy/784508
|
2020-07-16 15:32:59 +08:00
|
|
|
|
2023-02-05 04:15:01 +08:00
|
|
|
let copy = document.createElement('canvas').getContext('2d');
|
|
|
|
let pixels = this.ctx.getImageData(0, 0, this.width, this.height);
|
|
|
|
let i;
|
|
|
|
let bound = {
|
|
|
|
top: null,
|
|
|
|
left: null,
|
|
|
|
right: null,
|
|
|
|
bottom: null
|
|
|
|
};
|
|
|
|
let x, y;
|
|
|
|
|
|
|
|
for (i = 0; i < pixels.data.length; i += 4) {
|
|
|
|
if (pixels.data[i+3] !== 0) {
|
|
|
|
x = (i / 4) % this.width;
|
|
|
|
y = ~~((i / 4) / this.width);
|
|
|
|
|
|
|
|
if (bound.top === null) {
|
|
|
|
bound.top = y;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bound.left === null) {
|
|
|
|
bound.left = x;
|
|
|
|
} else if (x < bound.left) {
|
|
|
|
bound.left = x;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bound.right === null) {
|
|
|
|
bound.right = x;
|
|
|
|
} else if (bound.right < x) {
|
|
|
|
bound.right = x;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bound.bottom === null) {
|
|
|
|
bound.bottom = y;
|
|
|
|
} else if (bound.bottom < y) {
|
|
|
|
bound.bottom = y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-25 18:50:24 +08:00
|
|
|
var trimHeight = bound.bottom - bound.top + 1,
|
|
|
|
trimWidth = bound.right - bound.left + 1,
|
2023-02-05 04:15:01 +08:00
|
|
|
trimmed = this.ctx.getImageData(bound.left, bound.top, trimWidth, trimHeight);
|
|
|
|
|
|
|
|
copy.canvas.width = trimWidth;
|
|
|
|
copy.canvas.height = trimHeight;
|
|
|
|
copy.putImageData(trimmed, 0, 0);
|
|
|
|
this.canvas = copy.canvas;
|
|
|
|
this.ctx = copy;
|
|
|
|
}
|
2020-07-16 15:32:59 +08:00
|
|
|
}
|