You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, frameThickness = 50, frameBaseColor = "#8B4513", jaggedness = 15, numSegmentsPerSide = 10, applySepiaToImage = 1) {
// Helper function to adjust HEX color brightness (for texture)
// percent is -1.0 (black) to 1.0 (white), 0 is no change.
function adjustHexColor(hex, percent) {
let r = parseInt(hex.slice(1, 3), 16);
let g = parseInt(hex.slice(3, 5), 16);
let b = parseInt(hex.slice(5, 7), 16);
r = Math.round(Math.min(255, Math.max(0, r * (1 + percent))));
g = Math.round(Math.min(255, Math.max(0, g * (1 + percent))));
b = Math.round(Math.min(255, Math.max(0, b * (1 + percent))));
const rHex = r.toString(16).padStart(2, '0');
const gHex = g.toString(16).padStart(2, '0');
const bHex = b.toString(16).padStart(2, '0');
return `#${rHex}${gHex}${bHex}`;
}
// Helper function to create a jagged rectangular path
function createJaggedRectPath(ctx, x, y, w, h, numSegments, jaggednessAmount) {
const rand = (scale = 1) => (Math.random() - 0.5) * jaggednessAmount * 2 * scale;
ctx.moveTo(x + rand(0.5), y + rand(0.5)); // Start near top-left
// Top edge
for (let i = 1; i <= numSegments; i++) {
// Distribute points somewhat evenly but with randomness
const progress = i / numSegments;
const targetX = x + w * progress;
// Jitter points around the target X for this segment
const currentX = targetX + rand(0.5 / numSegments);
ctx.lineTo(currentX, y + rand());
}
ctx.lineTo(x + w + rand(0.5), y + rand(0.5)); // Ensure near top-right
// Right edge
for (let i = 1; i <= numSegments; i++) {
const progress = i / numSegments;
const targetY = y + h * progress;
const currentY = targetY + rand(0.5 / numSegments);
ctx.lineTo(x + w + rand(), currentY);
}
ctx.lineTo(x + w + rand(0.5), y + h + rand(0.5)); // Ensure near bottom-right
// Bottom edge
for (let i = 1; i <= numSegments; i++) {
const progress = i / numSegments;
const targetX = x + w * (1 - progress); // Iterate from right to left
const currentX = targetX + rand(0.5 / numSegments);
ctx.lineTo(currentX, y + h + rand());
}
ctx.lineTo(x + rand(0.5), y + h + rand(0.5)); // Ensure near bottom-left
// Left edge
for (let i = 1; i <= numSegments; i++) {
const progress = i / numSegments;
const targetY = y + h * (1 - progress); // Iterate from bottom to top
const currentY = targetY + rand(0.5 / numSegments);
ctx.lineTo(x + rand(), currentY);
}
// closePath() will connect the last point to the initial moveTo point.
}
const imgW = originalImg.naturalWidth || originalImg.width;
const imgH = originalImg.naturalHeight || originalImg.height;
if (!(imgW > 0 && imgH > 0)) {
console.error("Image has zero width or height. Cannot process.");
const errCanvas = document.createElement('canvas');
errCanvas.width = 100; errCanvas.height = 30;
const errCtx = errCanvas.getContext('2d');
errCtx.fillStyle = 'red';
errCtx.fillRect(0,0,100,30);
errCtx.fillStyle = 'white';
errCtx.fillText("Invalid Image", 10, 20);
return errCanvas;
}
const outCanvas = document.createElement('canvas');
const outCtx = outCanvas.getContext('2d');
// Adjust frameThickness if it's too large relative to image size
const maxFrameThickness = Math.min(imgW / 2, imgH / 2, frameThickness);
const actualFrameThickness = Math.max(0, maxFrameThickness);
outCanvas.width = imgW + 2 * actualFrameThickness;
outCanvas.height = imgH + 2 * actualFrameThickness;
// 1. Draw Frame Background (Solid Color)
outCtx.fillStyle = frameBaseColor;
outCtx.fillRect(0, 0, outCanvas.width, outCanvas.height);
// 2. Add Speckle Texture to Frame
// Apply texture only to the frame area if frameThickness > 0
if (actualFrameThickness > 0) {
const numSpeckles = Math.floor((outCanvas.width * outCanvas.height - imgW * imgH) * 0.015); // Density relative to frame area
for (let i = 0; i < numSpeckles; i++) {
// Randomly pick a point. If it's not in the image area, draw speckle.
const speckleX = Math.random() * outCanvas.width;
const speckleY = Math.random() * outCanvas.height;
if (speckleX < actualFrameThickness || speckleX >= outCanvas.width - actualFrameThickness ||
speckleY < actualFrameThickness || speckleY >= outCanvas.height - actualFrameThickness)
{
const colorVariation = (Math.random() * 0.5) - 0.25; // -25% to +25%
const speckleColor = adjustHexColor(frameBaseColor, colorVariation);
outCtx.fillStyle = speckleColor;
const speckleSize = Math.random() * 2.5 + 0.5;
outCtx.fillRect(speckleX, speckleY, speckleSize, speckleSize);
}
}
}
// 3. Prepare Image (Apply Sepia if needed)
let imageToDraw = originalImg;
if (applySepiaToImage === 1) {
const tempCanvas = document.createElement('canvas');
const tempCtx = tempCanvas.getContext('2d');
tempCanvas.width = imgW;
tempCanvas.height = imgH;
tempCtx.filter = 'sepia(1)';
tempCtx.drawImage(originalImg, 0, 0, imgW, imgH);
tempCtx.filter = 'none'; // Reset filter
imageToDraw = tempCanvas;
}
// 4. Create Jagged Clipping Path and Draw Image
outCtx.save();
outCtx.beginPath();
createJaggedRectPath(outCtx,
actualFrameThickness,
actualFrameThickness,
imgW,
imgH,
numSegmentsPerSide,
jaggedness
);
outCtx.closePath();
outCtx.clip();
outCtx.drawImage(imageToDraw, actualFrameThickness, actualFrameThickness, imgW, imgH);
outCtx.restore(); // Remove clipping path effects
// 5. Add inner shadow stroke to the edge of the image "opening"
if (jaggedness > 0 && actualFrameThickness > 0) {
outCtx.save();
outCtx.beginPath();
createJaggedRectPath(outCtx, actualFrameThickness, actualFrameThickness, imgW, imgH, numSegmentsPerSide, jaggedness);
outCtx.closePath();
outCtx.strokeStyle = 'rgba(0,0,0,0.3)';
// Make shadow width relative to jaggedness but not too large, ensure it's at least 1px
outCtx.lineWidth = Math.max(1, Math.min(jaggedness * 0.2, actualFrameThickness * 0.1));
outCtx.stroke();
outCtx.restore();
}
return outCanvas;
}
Apply Changes