You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, borderWidth = 40, borderColor1 = "#006400", borderColor2 = "#FFD700", cornerMotifEnabled = 1, cornerMotifSizeScale = 0.7) {
// Helper function to draw a Celtic Triskele-like motif
// Draws a three-armed spiral motif.
function drawCelticTriskeleMotif(ctx, centerX, centerY, size, motifColor) {
ctx.save();
ctx.strokeStyle = motifColor;
// Line width scales with motif size, with a minimum
ctx.lineWidth = Math.max(1.5, size / 12);
ctx.lineCap = 'round'; // Rounded ends for smoother strokes
ctx.lineJoin = 'round'; // Rounded joins for smoother connections
const numArms = 3;
for (let i = 0; i < numArms; i++) {
// Calculate the base angle for the current arm
const angle = (i * 2 * Math.PI / numArms);
ctx.beginPath();
// Each arm starts from the center and curves outwards, then curls back.
// A cubic Bezier curve is used for a smooth, flowing swirl.
ctx.moveTo(centerX, centerY); // Start arm at the motif's center
// Control point 1: slightly offset from center along the arm's initial direction.
// This helps the curve emerge smoothly from the congested center point.
const cp1Radius = size * 0.05; // Small radius for the first control point
const cp1Angle = angle + Math.PI / 6; // ~30 degrees offset for initial direction
const cp1X = centerX + cp1Radius * Math.cos(cp1Angle);
const cp1Y = centerY + cp1Radius * Math.sin(cp1Angle);
// Control point 2: defines the main outward sweep and width of the arm.
// Positioned further out to create the curve's peak.
const cp2Radius = size * 0.5; // Radius for the second control point (main body of swirl)
const cp2Angle = angle + Math.PI / 3; // ~60 degrees offset for the curve's widest part
const cp2X = centerX + cp2Radius * Math.cos(cp2Angle);
const cp2Y = centerY + cp2Radius * Math.sin(cp2Angle);
// End point: where the arm's tip curls inwards, completing the swirl.
const endRadius = size * 0.35; // Radius for the endpoint (tip of the swirl)
const endAngle = angle + Math.PI / 1.5; // ~120 degrees offset, bringing the tip inwards
const endX = centerX + endRadius * Math.cos(endAngle);
const endY = centerY + endRadius * Math.sin(endAngle);
ctx.bezierCurveTo(cp1X, cp1Y, cp2X, cp2Y, endX, endY);
ctx.stroke(); // Draw the arm
}
ctx.restore();
}
const imgWidth = originalImg.width;
const imgHeight = originalImg.height;
// Handle cases where the image might not be loaded or has no dimensions.
if (!originalImg || imgWidth === 0 || imgHeight === 0) {
const errorCanvas = document.createElement('canvas');
errorCanvas.width = 150;
errorCanvas.height = 50;
const errCtx = errorCanvas.getContext('2d');
if (errCtx) {
errCtx.fillStyle = '#FDD'; // Light red background
errCtx.fillRect(0, 0, errorCanvas.width, errorCanvas.height);
errCtx.fillStyle = '#D00'; // Dark red text
errCtx.font = '14px Arial';
errCtx.textAlign = 'center';
errCtx.textBaseline = 'middle';
errCtx.fillText('Invalid Image Input', errorCanvas.width / 2, errorCanvas.height / 2);
}
return errorCanvas;
}
// Ensure borderWidth is not negative.
borderWidth = Math.max(0, Number(borderWidth));
cornerMotifSizeScale = Math.max(0.1, Math.min(1.0, Number(cornerMotifSizeScale))); // Clamp scale [0.1, 1.0]
const canvas = document.createElement('canvas');
canvas.width = imgWidth + 2 * borderWidth;
canvas.height = imgHeight + 2 * borderWidth;
const ctx = canvas.getContext('2d');
if (!ctx) {
// Fallback if canvas context cannot be retrieved (highly unlikely in modern browsers)
console.error("Canvas 2D context could not be retrieved.");
// Return a minimal representation or throw error as per broader application design.
// For this function, returning an empty (or minimal error) canvas.
const errorCanvas = document.createElement('canvas');
errorCanvas.width = 1; errorCanvas.height = 1;
return errorCanvas;
}
// 1. Fill the entire canvas with the main border color (borderColor1).
// This forms the background of the border. The image will be drawn over the central part.
if (borderWidth > 0) {
ctx.fillStyle = borderColor1;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
// 2. Draw corner motifs if enabled and the border is wide enough for them.
if (borderWidth > 0 && cornerMotifEnabled == 1) { // Using == for number 1 vs string "1" flexibility
const motifActualSize = borderWidth * cornerMotifSizeScale;
// Only draw motifs if they are large enough to be discerned.
if (motifActualSize >= 5) { // Min size for a motif to look reasonable.
const halfBorderWidth = borderWidth / 2;
// Top-left corner
drawCelticTriskeleMotif(ctx, halfBorderWidth, halfBorderWidth, motifActualSize, borderColor2);
// Top-right corner
drawCelticTriskeleMotif(ctx, canvas.width - halfBorderWidth, halfBorderWidth, motifActualSize, borderColor2);
// Bottom-left corner
drawCelticTriskeleMotif(ctx, halfBorderWidth, canvas.height - halfBorderWidth, motifActualSize, borderColor2);
// Bottom-right corner
drawCelticTriskeleMotif(ctx, canvas.width - halfBorderWidth, canvas.height - halfBorderWidth, motifActualSize, borderColor2);
}
}
// 3. Draw the original image onto the canvas, offset by the border width.
ctx.drawImage(originalImg, borderWidth, borderWidth, imgWidth, imgHeight);
// 4. Draw an inner accent frame around the image.
// This line visually separates the image from the border and adds a finished look.
if (borderWidth > 3) { // Only add frame if border is somewhat substantial.
ctx.strokeStyle = borderColor2; // Use the accent color for the frame.
ctx.lineWidth = Math.max(1, borderWidth * 0.06); // Frame thickness relative to border width.
// Calculate offset for the strokeRect to be centered on the image edge.
// Half of the line will be on the image, half on the border background.
const lineOffset = ctx.lineWidth / 2;
ctx.strokeRect(
borderWidth - lineOffset,
borderWidth - lineOffset,
imgWidth + ctx.lineWidth, // Add lineWidth to cover full extent
imgHeight + ctx.lineWidth // Add lineWidth to cover full extent
);
}
return canvas;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Celtic Illuminated Manuscript Image Creator is an online tool that transforms standard images into beautifully framed artworks inspired by Celtic manuscript designs. Users can enhance their images by adding a decorative border with customizable width and colors, as well as decorative corner motifs resembling traditional Celtic patterns. This tool is ideal for creating unique visual presentations, enhancing personal photos, or producing artwork for invitations, greeting cards, and other creative projects. It adds an artistic touch to visuals, making them suitable for exhibitions, personal display, or gifts.