You can edit the below JavaScript code to customize the image tool.
async function processImage(originalImg, vignetteStrength = 0.5, blurAmount = 2, sepiaTone = 0.3, textureOpacity = 0.1, borderStyle = 'ornate') {
// 1. Create a canvas and get the 2D context
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Use naturalWidth/Height to get the original image dimensions.
// This is important because the img element might be styled with CSS.
const w = originalImg.naturalWidth;
const h = originalImg.naturalHeight;
// Handle cases where the image isn't loaded or has no dimensions.
if (w === 0 || h === 0) {
console.error("Image has not loaded or has zero dimensions.");
canvas.width = 1;
canvas.height = 1;
return canvas;
}
canvas.width = w;
canvas.height = h;
// Ensure parameters are valid numbers, providing defaults if not.
const numVignetteStrength = Math.max(0, Math.min(1, Number(vignetteStrength))) || 0;
const numBlurAmount = Math.max(0, Number(blurAmount)) || 0;
const numSepiaTone = Math.max(0, Math.min(1, Number(sepiaTone))) || 0;
const numTextureOpacity = Math.max(0, Math.min(1, Number(textureOpacity))) || 0;
// 2. Apply image filters and draw the original image
// The filter property allows applying CSS-like filters directly to the canvas context.
// This creates the soft, vintage, dreamy base for our storybook effect.
ctx.filter = `blur(${numBlurAmount}px) sepia(${numSepiaTone})`;
ctx.drawImage(originalImg, 0, 0, w, h);
// Reset the filter so it doesn't affect subsequent drawings (like the texture and border).
ctx.filter = 'none';
// 3. Add a paper/canvas texture overlay
if (numTextureOpacity > 0) {
// 'overlay' blend mode works well for adding texture without washing out the image.
ctx.globalCompositeOperation = 'overlay';
ctx.fillStyle = '#808080'; // A neutral gray is ideal for overlay blending.
// Draw a large number of tiny, semi-transparent rectangles to simulate noise/texture.
// The number of particles is proportional to the image area.
const noiseAmount = (w * h) / 10;
for (let i = 0; i < noiseAmount; i++) {
const x = Math.random() * w;
const y = Math.random() * h;
// Vary the alpha for a more natural texture.
const alpha = Math.random() * numTextureOpacity;
ctx.globalAlpha = alpha;
// Using 2x2 pixels gives a slightly coarser, more visible texture than 1x1.
ctx.fillRect(x, y, 2, 2);
}
// Reset composite operation and alpha for the next steps.
ctx.globalCompositeOperation = 'source-over';
ctx.globalAlpha = 1.0;
}
// 4. Add a vignette effect (darker corners) to focus attention on the center
if (numVignetteStrength > 0) {
// Create a radial gradient from the center outwards.
const gradient = ctx.createRadialGradient(
w / 2, h / 2, Math.min(w, h) * 0.2, // Inner circle (transparent)
w / 2, h / 2, Math.max(w, h) * 0.8 // Outer circle (dark)
);
gradient.addColorStop(0, 'rgba(0,0,0,0)');
gradient.addColorStop(1, `rgba(0,0,0,${numVignetteStrength})`);
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, w, h);
}
// 5. Add a decorative border based on the selected style
const borderColor = 'rgba(50, 40, 30, 0.75)'; // A dark, slightly transparent brown
switch (borderStyle) {
case 'simple': {
const borderWidth = Math.min(w, h) * 0.03;
ctx.strokeStyle = borderColor;
// Outer thin line
ctx.lineWidth = Math.max(1, borderWidth * 0.1);
const outerMargin = borderWidth * 0.5;
ctx.strokeRect(outerMargin, outerMargin, w - outerMargin * 2, h - outerMargin * 2);
// Inner thick line
ctx.lineWidth = Math.max(1, borderWidth * 0.3);
const innerMargin = borderWidth;
ctx.strokeRect(innerMargin, innerMargin, w - innerMargin * 2, h - innerMargin * 2);
break;
}
case 'ornate': {
const padding = Math.min(w, h) * 0.04;
const fontSize = Math.max(12, padding * 0.9);
const ornament = '❦'; // Unicode: FLORAL HEART (a nice storybook-style character)
ctx.fillStyle = borderColor;
ctx.font = `${fontSize}px Georgia, serif`; // Use a common, web-safe serif font
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
// Draw corner ornaments
ctx.fillText(ornament, padding, padding); // Top-left
ctx.fillText(ornament, w - padding, padding); // Top-right
ctx.fillText(ornament, padding, h - padding); // Bottom-left
ctx.fillText(ornament, w - padding, h - padding); // Bottom-right
// Draw connecting lines for the frame
ctx.strokeStyle = borderColor;
ctx.lineWidth = Math.max(1, fontSize * 0.03);
const lineOffset = fontSize * 0.5; // Offset to not draw over the ornament center
ctx.beginPath();
// Top line
ctx.moveTo(padding + lineOffset, padding);
ctx.lineTo(w - padding - lineOffset, padding);
// Right line
ctx.moveTo(w - padding, padding + lineOffset);
ctx.lineTo(w - padding, h - padding - lineOffset);
// Bottom line
ctx.moveTo(padding + lineOffset, h - padding);
ctx.lineTo(w - padding - lineOffset, h - padding);
// Left line
ctx.moveTo(padding, padding + lineOffset);
ctx.lineTo(padding, h - padding - lineOffset);
ctx.stroke();
break;
}
case 'none':
default:
// Do nothing for 'none' or unknown styles
break;
}
// 6. Return the final canvas element, which can be appended to the DOM.
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 Image Storybook Creator is an online tool designed to enhance and transform images into a storybook-like aesthetic. Users can apply various artistic effects such as blur, sepia tone, and texture overlays to create a dreamy, vintage atmosphere. Additionally, the tool offers customization options for vignette strength to focus attention on the center of the image and decorative borders in different styles, enhancing the overall presentation. This tool is ideal for creating visually appealing graphics for children’s books, invitations, or any project where a whimsical touch is desired.