You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, papyrusBorderWidthStr = "50", edgeRoughnessStr = "15") {
const papyrusBorderWidth = parseInt(papyrusBorderWidthStr, 10) || 50;
let edgeRoughness = parseInt(edgeRoughnessStr, 10) || 15;
// Ensure edgeRoughness is not excessively large compared to borderWidth
edgeRoughness = Math.min(edgeRoughness, papyrusBorderWidth * 0.8);
// Ensure edgeRoughness is not negative
edgeRoughness = Math.max(0, edgeRoughness);
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = originalImg.width + 2 * papyrusBorderWidth;
canvas.height = originalImg.height + 2 * papyrusBorderWidth;
const segmentsPerSide = 20; // Number of segments for jagged edges
// Helper function to create a jagged path as a Path2D object
function createJaggedPath2D(pathX, pathY, pathWidth, pathHeight, numSegments, magnitude) {
const path = new Path2D();
let x, y;
// Start point (top-left corner, randomized)
path.moveTo(pathX + (Math.random() - 0.5) * magnitude * 2, pathY + (Math.random() - 0.5) * magnitude * 2);
// Top edge
for (let i = 1; i < numSegments; i++) {
x = pathX + (pathWidth / numSegments) * i;
path.lineTo(x, pathY + (Math.random() - 0.5) * magnitude * 2);
}
path.lineTo(pathX + pathWidth + (Math.random() - 0.5) * magnitude * 2, pathY + (Math.random() - 0.5) * magnitude * 2);
// Right edge
for (let i = 1; i < numSegments; i++) {
y = pathY + (pathHeight / numSegments) * i;
path.lineTo(pathX + pathWidth + (Math.random() - 0.5) * magnitude * 2, y);
}
path.lineTo(pathX + pathWidth + (Math.random() - 0.5) * magnitude * 2, pathY + pathHeight + (Math.random() - 0.5) * magnitude * 2);
// Bottom edge
for (let i = numSegments - 1; i >= 1; i--) {
x = pathX + (pathWidth / numSegments) * i;
path.lineTo(x, pathY + pathHeight + (Math.random() - 0.5) * magnitude * 2);
}
path.lineTo(pathX + (Math.random() - 0.5) * magnitude * 2, pathY + pathHeight + (Math.random() - 0.5) * magnitude * 2);
// Left edge
for (let i = numSegments - 1; i >= 1; i--) {
y = pathY + (pathHeight / numSegments) * i;
path.lineTo(pathX + (Math.random() - 0.5) * magnitude * 2, y);
}
path.closePath();
return path;
}
// Helper function to draw papyrus fibers
function drawPapyrusFibers(context, width, height) {
const numFibers = Math.floor((width * height) / 60); // Density of fibers
const baseR = 234, baseG = 220, baseB = 179; // Papyrus base color for reference
context.save();
context.globalAlpha = 0.7; // Fibers are somewhat transparent overall
// Horizontal fibers
for (let i = 0; i < numFibers / 2; i++) {
const y = Math.random() * height;
const alpha = 0.05 + Math.random() * 0.1; // Individual fiber alpha
const fiberR = Math.max(0, Math.min(255, baseR - 30 - (Math.random() * 40)));
const fiberG = Math.max(0, Math.min(255, baseG - 30 - (Math.random() * 40)));
const fiberB = Math.max(0, Math.min(255, baseB - 40 - (Math.random() * 40)));
context.strokeStyle = `rgba(${Math.floor(fiberR)}, ${Math.floor(fiberG)}, ${Math.floor(fiberB)}, ${alpha})`;
context.lineWidth = 0.5 + Math.random() * 1.5;
context.beginPath();
context.moveTo(0, y);
context.lineTo(width, y + (Math.random() - 0.5) * 8); // Slightly wavy
context.stroke();
}
// Vertical fibers
for (let i = 0; i < numFibers / 2; i++) {
const x = Math.random() * width;
const alpha = 0.05 + Math.random() * 0.1;
const fiberR = Math.max(0, Math.min(255, baseR - 30 - (Math.random() * 40)));
const fiberG = Math.max(0, Math.min(255, baseG - 30 - (Math.random() * 40)));
const fiberB = Math.max(0, Math.min(255, baseB - 40 - (Math.random() * 40)));
context.strokeStyle = `rgba(${Math.floor(fiberR)}, ${Math.floor(fiberG)}, ${Math.floor(fiberB)}, ${alpha})`;
context.lineWidth = 0.5 + Math.random() * 1.5;
context.beginPath();
context.moveTo(x, 0);
context.lineTo(x + (Math.random() - 0.5) * 8, height); // Slightly wavy
context.stroke();
}
context.restore();
}
// 1. Create the jagged path for the papyrus shape
const papyrusShapePath = createJaggedPath2D(0, 0, canvas.width, canvas.height, segmentsPerSide, edgeRoughness);
// 2. Clip to this path and draw the papyrus texture
ctx.save();
ctx.clip(papyrusShapePath);
// Draw papyrus base color
ctx.fillStyle = '#EADCB3'; // Papyrus beige color
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw papyrus fibers
drawPapyrusFibers(ctx, canvas.width, canvas.height);
ctx.restore(); // Remove clipping
// 3. Optional: Add a subtle darker stroke to the edges of the papyrus for depth
ctx.strokeStyle = 'rgba(100, 80, 50, 0.2)'; // Darker, semi-transparent brown
ctx.lineWidth = Math.max(1, edgeRoughness / 8); // Thin line for edge definition
ctx.stroke(papyrusShapePath);
// 4. Draw the original image onto the papyrus
ctx.save();
// Add a shadow to make the image pop from the papyrus
ctx.shadowColor = 'rgba(0, 0, 0, 0.35)';
ctx.shadowBlur = 10;
ctx.shadowOffsetX = 3;
ctx.shadowOffsetY = 3;
ctx.drawImage(originalImg, papyrusBorderWidth, papyrusBorderWidth, originalImg.width, originalImg.height);
ctx.restore();
return canvas;
}
Apply Changes