You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, numDripsParam = 75, sampleColorStr = "true", fixedDripColor = "black", maxDripLengthParam = 150, minDripThicknessParam = 3, maxDripThicknessParam = 10, originYSpreadFactorParam = 0.5) {
// Validate originalImg
if (!originalImg || typeof originalImg.width === 'undefined' || originalImg.width === 0 || typeof originalImg.height === 'undefined' || originalImg.height === 0) {
console.warn("Image Drip Paint Filter: Invalid image provided or image not loaded.");
const fallbackCanvas = document.createElement('canvas');
fallbackCanvas.width = (originalImg && originalImg.width > 0) ? originalImg.width : 100;
fallbackCanvas.height = (originalImg && originalImg.height > 0) ? originalImg.height : 100;
const fbCtx = fallbackCanvas.getContext('2d');
if (fbCtx) {
fbCtx.fillStyle = "#cccccc";
fbCtx.fillRect(0,0,fallbackCanvas.width, fallbackCanvas.height);
fbCtx.fillStyle = "black";
fbCtx.font = "12px Arial";
fbCtx.textAlign = "center";
fbCtx.textBaseline = "middle";
fbCtx.fillText("Invalid Image", fallbackCanvas.width/2, fallbackCanvas.height/2);
}
return fallbackCanvas;
}
// Parameter parsing and validation
const sampleColor = String(sampleColorStr).toLowerCase() === "true";
let numDrips = parseInt(String(numDripsParam), 10);
if (isNaN(numDrips) || numDrips < 0) numDrips = 75;
let maxDripLength = parseFloat(String(maxDripLengthParam));
if (isNaN(maxDripLength) || maxDripLength <= 0) maxDripLength = 150;
let minDripThickness = parseFloat(String(minDripThicknessParam));
if (isNaN(minDripThickness) || minDripThickness <= 0) minDripThickness = 3;
let maxDripThickness = parseFloat(String(maxDripThicknessParam));
if (isNaN(maxDripThickness) || maxDripThickness <= 0) maxDripThickness = 10;
if (minDripThickness > maxDripThickness) {
maxDripThickness = minDripThickness + Math.max(1, minDripThickness * 0.2);
}
if (maxDripThickness < minDripThickness) { // If max was initially smaller
maxDripThickness = minDripThickness;
}
let originYSpreadFactor = parseFloat(String(originYSpreadFactorParam));
if (isNaN(originYSpreadFactor) || originYSpreadFactor < 0 || originYSpreadFactor > 1) originYSpreadFactor = 0.5;
const canvas = document.createElement('canvas');
canvas.width = originalImg.width;
canvas.height = originalImg.height + maxDripLength;
const ctx = canvas.getContext('2d');
if (!ctx) {
console.error("Image Drip Paint Filter: Could not get 2D context for canvas.");
return originalImg; // Return original image or some error indicator
}
// Draw the original image onto the main canvas
ctx.drawImage(originalImg, 0, 0);
let tempSampleCanvas = null;
let tempSampleCtx = null;
let canSampleColor = sampleColor; // Flag to track if sampling is possible
if (sampleColor) {
tempSampleCanvas = document.createElement('canvas');
tempSampleCanvas.width = originalImg.width;
tempSampleCanvas.height = originalImg.height;
tempSampleCtx = tempSampleCanvas.getContext('2d', { willReadFrequently: true });
if (!tempSampleCtx) {
console.warn("Image Drip Paint Filter: Failed to create sampling context. Using fixed drip color.");
canSampleColor = false;
} else {
try {
tempSampleCtx.drawImage(originalImg, 0, 0);
// Test getImageData to see if canvas is tainted early
tempSampleCtx.getImageData(0, 0, 1, 1);
} catch (e) {
console.warn("Image Drip Paint Filter: Error drawing to or sampling from temp canvas. Canvas might be tainted. Using fixed drip color. Error:", e);
canSampleColor = false;
}
}
}
function getPixelColor(x, y) {
if (!canSampleColor || !tempSampleCtx ) { // Check canSampleColor flag
return fixedDripColor;
}
// Clamp coordinates to be within the image bounds
x = Math.max(0, Math.min(Math.floor(x), originalImg.width - 1));
y = Math.max(0, Math.min(Math.floor(y), originalImg.height - 1));
try {
const pixelData = tempSampleCtx.getImageData(x, y, 1, 1).data;
return `rgba(${pixelData[0]}, ${pixelData[1]}, ${pixelData[2]}, ${pixelData[3] / 255})`;
} catch (e) {
// This catch might be redundant if initial test failed, but good for safety
console.warn("Image Drip Paint Filter: Error sampling pixel color during getPixelColor. Using fixed color. Error:", e);
canSampleColor = false; // Stop trying to sample for subsequent drips
return fixedDripColor;
}
}
function drawRealisticDrip(context, startX, startY, length, dripInitialThickness, color) {
let currentX = startX;
let currentY = startY;
context.fillStyle = color;
const numSegments = Math.max(5, Math.ceil(length / Math.max(1, dripInitialThickness * 0.4)));
const speedVariation = 0.4;
const wiggleScale = dripInitialThickness * 0.35;
for (let i = 0; i <= numSegments; i++) {
const t = i / numSegments;
context.beginPath();
context.arc(currentX, currentY, dripInitialThickness / 2, 0, Math.PI * 2);
context.fill();
if (i === numSegments) break;
const baseSegmentYMovement = length / numSegments;
let yMovement = baseSegmentYMovement * (1 + (Math.random() - 0.5) * speedVariation);
yMovement = Math.max(0.5, yMovement);
currentY += yMovement;
if (currentY > startY + length) {
currentY = startY + length;
}
const G_wiggleFactor = (1 - t * t) * wiggleScale;
currentX += (Math.random() - 0.5) * G_wiggleFactor;
currentX = Math.max(dripInitialThickness / 2, Math.min(context.canvas.width - dripInitialThickness / 2, currentX));
if (currentY >= context.canvas.height - dripInitialThickness / 2) {
currentY = context.canvas.height - dripInitialThickness / 2;
context.beginPath();
context.arc(currentX, currentY, (dripInitialThickness / 2) * 1.5, 0, Math.PI * 2);
context.fill();
return;
}
}
context.beginPath();
context.arc(currentX, currentY, (dripInitialThickness / 2) * 1.5, 0, Math.PI * 2);
context.fill();
}
for (let i = 0; i < numDrips; i++) {
const startX = Math.random() * originalImg.width;
const startY = Math.random() * (originalImg.height * originYSpreadFactor);
const dripColorToUse = getPixelColor(startX, startY);
const currentDripLength = (Math.random() * 0.6 + 0.4) * maxDripLength;
let currentThickness = minDripThickness + Math.random() * (maxDripThickness - minDripThickness);
if (maxDripThickness === minDripThickness) currentThickness = minDripThickness;
drawRealisticDrip(ctx, startX, startY, currentDripLength, currentThickness, dripColorToUse);
}
return canvas;
}
Apply Changes