You can edit the below JavaScript code to customize the image tool.
Apply Changes
/**
* Creates a photostrip effect from a single image by repeating it in a strip.
*
* @param {HTMLImageElement} originalImg The original image object to be repeated in the strip.
* @param {number} numFrames The total number of frames in the photostrip. Defaults to 4.
* @param {string} orientation The orientation of the strip ('vertical' or 'horizontal'). Defaults to 'vertical'.
* @param {number} spacing The space in pixels between each photo frame. Defaults to 10.
* @param {string} stripColor A CSS color string for the background color of the photostrip film. Defaults to '#FFFFFF' (white).
* @param {number} padding The padding in pixels around the photos, creating the border. Defaults to 25.
* @param {string} addPerforations Whether to add film sprocket holes ('true' or 'false'). Defaults to 'true'.
* @param {number} frameWidth The width of each individual photo frame. The height is calculated automatically to maintain the aspect ratio. Defaults to 250.
* @returns {HTMLCanvasElement} A canvas element containing the generated photostrip image.
*/
function processImage(
originalImg,
numFrames = 4,
orientation = 'vertical',
spacing = 10,
stripColor = '#FFFFFF',
padding = 25,
addPerforations = 'true',
frameWidth = 250
) {
// 1. Parameter Sanity Checks & Type Coercion
const pNumFrames = parseInt(numFrames, 10) || 4;
const pOrientation = String(orientation).toLowerCase();
const pSpacing = Math.max(0, parseInt(spacing, 10) || 10);
const pStripColor = String(stripColor);
const pPadding = Math.max(0, parseInt(padding, 10) || 25);
const pAddPerforations = String(addPerforations).toLowerCase() === 'true';
const pFrameWidth = Math.max(1, parseInt(frameWidth, 10) || 250);
// 2. Calculate Dimensions
const aspectRatio = originalImg.naturalHeight / originalImg.naturalWidth;
const frameHeight = pFrameWidth * aspectRatio;
const totalPadding = 2 * pPadding;
let canvasWidth, canvasHeight;
if (pOrientation === 'horizontal') {
canvasWidth = (pNumFrames * pFrameWidth) + ((pNumFrames - 1) * pSpacing) + totalPadding;
canvasHeight = frameHeight + totalPadding;
} else { // 'vertical' is the default
canvasWidth = pFrameWidth + totalPadding;
canvasHeight = (pNumFrames * frameHeight) + ((pNumFrames - 1) * pSpacing) + totalPadding;
}
// 3. Setup Canvas
const canvas = document.createElement('canvas');
canvas.width = canvasWidth;
canvas.height = canvasHeight;
const ctx = canvas.getContext('2d');
// 4. Draw Background
ctx.fillStyle = pStripColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 5. Draw Image Frames
for (let i = 0; i < pNumFrames; i++) {
let x, y;
if (pOrientation === 'horizontal') {
x = pPadding + i * (pFrameWidth + pSpacing);
y = pPadding;
} else {
x = pPadding;
y = pPadding + i * (frameHeight + pSpacing);
}
// Add a subtle shadow for each photo for a 3D effect
ctx.shadowColor = 'rgba(0, 0, 0, 0.4)';
ctx.shadowBlur = 8;
ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;
ctx.drawImage(originalImg, x, y, pFrameWidth, frameHeight);
// Reset shadow for subsequent drawings
ctx.shadowColor = 'transparent';
}
// 6. Draw Film Perforations (Sprocket Holes)
if (pAddPerforations && pPadding >= 15) {
ctx.fillStyle = '#444444';
const holeSize = Math.max(4, Math.floor(pPadding / 5));
const holeRadius = holeSize / 2;
if (pOrientation === 'horizontal') {
const yTop = pPadding / 2;
const yBottom = canvas.height - pPadding / 2;
// Draw a single perforation set above/below the center of each frame
for (let i = 0; i < pNumFrames; i++) {
const x = pPadding + i * (pFrameWidth + pSpacing) + pFrameWidth / 2;
// Top hole
ctx.beginPath();
if (ctx.roundRect) {
ctx.roundRect(x - holeSize * 1.5, yTop - holeRadius, holeSize * 3, holeSize, holeRadius);
} else { // Fallback for older browsers
ctx.rect(x - holeSize * 1.5, yTop - holeRadius, holeSize * 3, holeSize);
}
ctx.fill();
// Bottom hole
ctx.beginPath();
if (ctx.roundRect) {
ctx.roundRect(x - holeSize * 1.5, yBottom - holeRadius, holeSize * 3, holeSize, holeRadius);
} else {
ctx.rect(x - holeSize * 1.5, yBottom - holeRadius, holeSize * 3, holeSize);
}
ctx.fill();
}
} else { // Vertical orientation
const xLeft = pPadding / 2;
const xRight = canvas.width - pPadding / 2;
// Place perforations in the gaps between the photo frames
for (let i = 0; i < pNumFrames - 1; i++) {
const y = pPadding + (i + 1) * frameHeight + (i + 0.5) * pSpacing;
// Left side hole
ctx.beginPath();
if (ctx.roundRect) {
ctx.roundRect(xLeft - holeRadius, y - holeSize * 1.5, holeSize, holeSize * 3, holeRadius);
} else {
ctx.rect(xLeft - holeRadius, y - holeSize * 1.5, holeSize, holeSize * 3);
}
ctx.fill();
// Right side hole
ctx.beginPath();
if (ctx.roundRect) {
ctx.roundRect(xRight - holeRadius, y - holeSize * 1.5, holeSize, holeSize * 3, holeRadius);
} else {
ctx.rect(xRight - holeRadius, y - holeSize * 1.5, holeSize, holeSize * 3);
}
ctx.fill();
}
}
}
// 7. Return the completed canvas
return canvas;
}
Apply Changes