You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, pointCount = 1500, wireframe = 'false', strokeColor = 'rgba(0,0,0,0.1)', strokeWidth = 1) {
/**
* Dynamically imports the Delaunator library for triangulation.
* Caches it on the window object to prevent re-downloads on subsequent calls.
*/
if (typeof window.Delaunator === 'undefined') {
try {
// Using a reliable CDN link for the ES module.
const module = await import('https://unpkg.com/delaunator@5.0.0/index.js');
window.Delaunator = module.default;
} catch (error) {
console.error("Failed to load Delaunator library:", error);
// Fallback: return the original image on a canvas if the library fails to load.
const canvas = document.createElement('canvas');
canvas.width = originalImg.naturalWidth;
canvas.height = originalImg.naturalHeight;
const ctx = canvas.getContext('2d');
ctx.drawImage(originalImg, 0, 0);
return canvas;
}
}
const Delaunator = window.Delaunator;
const w = originalImg.naturalWidth;
const h = originalImg.naturalHeight;
// Create a temporary canvas to access the image's pixel data efficiently.
const tempCanvas = document.createElement('canvas');
tempCanvas.width = w;
tempCanvas.height = h;
const tempCtx = tempCanvas.getContext('2d');
tempCtx.drawImage(originalImg, 0, 0, w, h);
const imageData = tempCtx.getImageData(0, 0, w, h);
const data = imageData.data;
/**
* Helper function to get the RGBA color at a specific coordinate from the image data.
* @param {number} x - The x-coordinate.
* @param {number} y - The y-coordinate.
* @returns {string} The CSS rgba color string.
*/
const getColorAt = (x, y) => {
const roundedX = Math.max(0, Math.min(Math.floor(x), w - 1));
const roundedY = Math.max(0, Math.min(Math.floor(y), h - 1));
const index = (roundedY * w + roundedX) * 4;
const r = data[index];
const g = data[index + 1];
const b = data[index + 2];
const a = data[index + 3] / 255;
return `rgba(${r}, ${g}, ${b}, ${a})`;
};
// Create the final destination canvas.
const canvas = document.createElement('canvas');
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext('2d');
// Generate vertices for the triangulation.
const points = [];
// Add points at corners and edge midpoints to preserve the image boundary.
points.push([0, 0], [w, 0], [0, h], [w, h], [w / 2, 0], [w / 2, h], [0, h / 2], [w, h / 2]);
// Add a specified number of random points.
const numPoints = Number(pointCount) || 1500;
for (let i = 0; i < numPoints; i++) {
points.push([Math.random() * w, Math.random() * h]);
}
// Perform Delaunay triangulation on the points.
const delaunay = Delaunator.from(points);
const triangles = delaunay.triangles;
// Render each triangle by filling it with the color from its centroid.
for (let i = 0; i < triangles.length; i += 3) {
const p1_idx = triangles[i];
const p2_idx = triangles[i + 1];
const p3_idx = triangles[i + 2];
const [x1, y1] = points[p1_idx];
const [x2, y2] = points[p2_idx];
const [x3, y3] = points[p3_idx];
// Calculate the centroid of the triangle to sample the color from the original image.
const cx = (x1 + x2 + x3) / 3;
const cy = (y1 + y2 + y3) / 3;
const color = getColorAt(cx, cy);
// Draw the filled triangle.
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.lineTo(x3, y3);
ctx.closePath();
ctx.fillStyle = color;
ctx.fill();
}
// Optionally draw the wireframe on top in a separate loop for a clean look.
const drawWireframe = wireframe.toString().toLowerCase() === 'true';
if (drawWireframe) {
ctx.strokeStyle = strokeColor;
ctx.lineWidth = Number(strokeWidth) || 1;
for (let i = 0; i < triangles.length; i += 3) {
const p1_idx = triangles[i];
const p2_idx = triangles[i + 1];
const p3_idx = triangles[i + 2];
const [x1, y1] = points[p1_idx];
const [x2, y2] = points[p2_idx];
const [x3, y3] = points[p3_idx];
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.lineTo(x3, y3);
ctx.closePath();
ctx.stroke();
}
}
return canvas;
}
Apply Changes