You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, woodTint = '#3e2723', bookDensity = 1.0) {
const canvas = document.createElement('canvas');
const width = 800;
const height = 600;
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
// Simple pseudo-random number generator for consistent outputs
let seed = 1234567;
function random() {
seed = (seed * 9301 + 49297) % 233280;
return seed / 233280;
}
// Colors
const backWallColor = woodTint; // Darker tint for back
const shelfColor = '#5D4037';
const shelfHighlight = '#795548';
const sidePanelColor = '#4E342E';
const bookColors = [
'#b71c1c', '#0d47a1', '#1b5e20', '#f57f17',
'#4a148c', '#e65100', '#263238', '#558b2f',
'#880e4f', '#004d40', '#827717', '#bf360c',
'#006064', '#1a237e', '#311b92'
];
// 1. Draw back wall
ctx.fillStyle = backWallColor;
ctx.fillRect(0, 0, width, height);
// Add simple wood grain effect to back wall
ctx.fillStyle = 'rgba(0,0,0,0.15)';
for (let w = 0; w < height; w += 8) {
if (random() > 0.3) {
ctx.fillRect(0, w, width, random() * 4 + 1);
}
}
// Shelf layout configurations
const shelfSpacing = 200;
const shelfThickness = 20;
const shelvesCount = Math.floor(height / shelfSpacing); // 3 shelves
// 2. Draw shelves and objects
for (let i = 1; i <= shelvesCount; i++) {
const shelfY = i * shelfSpacing;
// Draw shadow under the shelf
ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
ctx.fillRect(0, shelfY, width, 25);
// Draw the main shelf body
ctx.fillStyle = shelfColor;
ctx.fillRect(0, shelfY - shelfThickness, width, shelfThickness);
// Shelf wood grain
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
ctx.fillRect(0, shelfY - shelfThickness + 4, width, 2);
ctx.fillRect(0, shelfY - shelfThickness + 10, width, 3);
ctx.fillRect(0, shelfY - shelfThickness + 16, width, 1);
// Draw shelf highlight (top edge)
ctx.fillStyle = shelfHighlight;
ctx.fillRect(0, shelfY - shelfThickness, width, 3);
// Draw books on this shelf
let currentX = 30; // start slightly offset from the left panel
// We will leave a gap on the 2nd shelf for our plush cameo
const isCameoShelf = (i === 2);
const cameoGapStart = 250;
const cameoGapEnd = 550;
while (currentX < width - 30) {
// Check if we need to leave space for the cameo
if (isCameoShelf && currentX > cameoGapStart - 30 && currentX < cameoGapEnd) {
currentX = cameoGapEnd + random() * 20;
continue;
}
// Adjust book density spacing
if (random() > (0.8 * bookDensity)) {
currentX += random() * 40; // Empty space gap
}
const bookWidth = 20 + random() * 35;
let bookHeight = 100 + random() * 70;
const distToShelf = shelfY - shelfThickness;
// Stop drawing if we exceed the right panel bounds
if (currentX + bookWidth > width - 30) break;
const color = bookColors[Math.floor(random() * bookColors.length)];
// Base book color
ctx.fillStyle = color;
ctx.fillRect(currentX, distToShelf - bookHeight, bookWidth, bookHeight);
// Decorative line 1
ctx.fillStyle = 'rgba(255, 255, 255, 0.2)';
ctx.fillRect(currentX + 5, distToShelf - bookHeight, 2, bookHeight);
// Decorative line 2
ctx.fillRect(currentX + bookWidth - 7, distToShelf - bookHeight, 2, bookHeight);
// Horizontal bands (Faux titles/accents)
ctx.fillStyle = 'rgba(255, 215, 0, 0.5)'; // Gold accent
const bandHeight = 15;
ctx.fillRect(currentX, distToShelf - bookHeight + 20, bookWidth, bandHeight);
if (random() > 0.5) {
ctx.fillRect(currentX, distToShelf - bandHeight - 15, bookWidth, bandHeight);
}
// Book spine shading (3D cylindrical illusion)
const shadowGrad = ctx.createLinearGradient(currentX, 0, currentX + bookWidth, 0);
shadowGrad.addColorStop(0, 'rgba(0,0,0,0.4)');
shadowGrad.addColorStop(0.3, 'rgba(255,255,255,0.1)');
shadowGrad.addColorStop(0.7, 'rgba(255,255,255,0.1)');
shadowGrad.addColorStop(1, 'rgba(0,0,0,0.5)');
ctx.fillStyle = shadowGrad;
ctx.fillRect(currentX, distToShelf - bookHeight, bookWidth, bookHeight);
currentX += bookWidth + random() * 3; // tiny gap between books
}
}
// 3. Draw Side Panels (Frame)
ctx.fillStyle = sidePanelColor;
ctx.fillRect(0, 0, 25, height);
ctx.fillRect(width - 25, 0, 25, height);
// Side panel inner shadow to create depth
ctx.fillStyle = 'rgba(0, 0, 0, 0.4)';
ctx.fillRect(25, 0, 8, height);
ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
ctx.fillRect(width - 25 - 8, 0, 8, height);
// Side panel highlights
ctx.fillStyle = 'rgba(255, 255, 255, 0.05)';
ctx.fillRect(0, 0, 4, height);
ctx.fillRect(width - 25, 0, 4, height);
// 4. Draw the Plush Cameo (originalImg)
// Positioned on the 2nd shelf (i=2)
const targetShelfY = 2 * shelfSpacing - shelfThickness;
// Calculate sizing to comfortably fit on the shelf
const maxImgWidth = cameoGapEnd - cameoGapStart - 20; // e.g., 280
const maxImgHeight = shelfSpacing - shelfThickness - 15; // e.g., 165
let imgW = originalImg.width;
let imgH = originalImg.height;
const scale = Math.min(maxImgWidth / imgW, maxImgHeight / imgH);
imgW *= scale;
imgH *= scale;
// Center it exactly in the gap
const imgX = (cameoGapStart + cameoGapEnd) / 2 - (imgW / 2);
const imgY = targetShelfY - imgH;
// Draw Drop Shadow for the cameo
ctx.save();
ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
ctx.filter = 'blur(8px)';
ctx.beginPath();
// Create an elliptical shadow right under the object
ctx.ellipse(imgX + imgW / 2, targetShelfY - 2, imgW / 2.5, imgW / 10 + 5, 0, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
// Finally, draw the image itself
ctx.drawImage(originalImg, imgX, imgY, imgW, imgH);
return canvas;
}
Apply Changes