You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, type = 'spiral', color = 'rgba(255, 255, 0, 0.8)', lineWidth = 2, orientation = 0) {
const canvas = document.createElement('canvas');
canvas.width = originalImg.width;
canvas.height = originalImg.height;
const ctx = canvas.getContext('2d');
// Draw the original image onto the canvas
ctx.drawImage(originalImg, 0, 0);
// Setup styles for the Golden Ratio overlay
ctx.strokeStyle = color;
ctx.lineWidth = Number(lineWidth) || 2;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
const phi = (1 + Math.sqrt(5)) / 2; // Golden ratio ~1.61803
// Draw Phi Grid if requested
if (type === 'grid') {
const r1 = 1 / (1 + phi + 1); // ~0.276
const r2 = (1 + phi) / (1 + phi + 1); // ~0.724
ctx.beginPath();
// Vertical lines
ctx.moveTo(canvas.width * r1, 0);
ctx.lineTo(canvas.width * r1, canvas.height);
ctx.moveTo(canvas.width * r2, 0);
ctx.lineTo(canvas.width * r2, canvas.height);
// Horizontal lines
ctx.moveTo(0, canvas.height * r1);
ctx.lineTo(canvas.width, canvas.height * r1);
ctx.moveTo(0, canvas.height * r2);
ctx.lineTo(canvas.width, canvas.height * r2);
ctx.stroke();
return canvas;
}
// Default to Fibonacci Spiral bounds
let ori = parseInt(orientation, 10);
if (isNaN(ori) || ori < 0 || ori > 7) ori = 0;
// Symmetries 4 to 7 represent rotated orientations starting top/bottom
const swapXY = [4, 5, 6, 7].includes(ori);
const natural_ratio = swapXY ? (1 / phi) : phi;
let bw, bh;
const imgRatio = canvas.width / canvas.height;
// Fit the maximum size golden rectangle within the original image boundary
if (imgRatio > natural_ratio) {
bh = canvas.height;
bw = bh * natural_ratio;
} else {
bw = canvas.width;
bh = bw / natural_ratio;
}
// Center the bounding unit
let bx = (canvas.width - bw) / 2;
let by = (canvas.height - bh) / 2;
// Defines sequence of square cuts per orientation (0: Left, 1: Top, 2: Right, 3: Bottom)
const orientations = [
{ seq: [0, 1, 2, 3], cw: true }, // 0: Normal Clockwise inward
{ seq: [0, 3, 2, 1], cw: false }, // 1: Starts Left, CCW inward
{ seq: [2, 1, 0, 3], cw: false }, // 2: Starts Right, CCW inward
{ seq: [2, 3, 0, 1], cw: true }, // 3: Starts Right, CW inward
{ seq: [1, 2, 3, 0], cw: true }, // 4: Starts Top, CW inward
{ seq: [1, 0, 3, 2], cw: false }, // 5: Starts Top, CCW inward
{ seq: [3, 2, 1, 0], cw: false }, // 6: Starts Bottom, CCW inward
{ seq: [3, 0, 1, 2], cw: true } // 7: Starts Bottom, CW inward
];
// Accurate geometric starting/ending angles mapping mathematically per step arc quadrant
const arcs = {
CW: {
0: { cx: 1, cy: 1, start: Math.PI, end: 1.5 * Math.PI },
1: { cx: 0, cy: 1, start: 1.5 * Math.PI, end: 2 * Math.PI },
2: { cx: 0, cy: 0, start: 0, end: 0.5 * Math.PI },
3: { cx: 1, cy: 0, start: 0.5 * Math.PI, end: Math.PI }
},
CCW: {
0: { cx: 1, cy: 0, start: Math.PI, end: 0.5 * Math.PI },
1: { cx: 1, cy: 1, start: 1.5 * Math.PI, end: Math.PI },
2: { cx: 0, cy: 1, start: 2 * Math.PI, end: 1.5 * Math.PI },
3: { cx: 0, cy: 0, start: 0.5 * Math.PI, end: 0 }
}
};
const config = orientations[ori];
const cw = config.cw;
const seq = config.seq;
const maxIterations = 16; // Safely runs mathematically enough layers effectively into pixel limitations
// Iteratively draw golden blocks and arcs
for (let i = 0; i < maxIterations; i++) {
let dir = seq[i % 4];
let S, sx, sy;
// Cut perfect geometric squares iteratively according to the sequence
if (dir === 0) { // L
S = bh; sx = bx; sy = by;
bx += S; bw -= S;
} else if (dir === 1) { // T
S = bw; sx = bx; sy = by;
by += S; bh -= S;
} else if (dir === 2) { // R
S = bh; sx = bx + bw - S; sy = by;
bw -= S;
} else if (dir === 3) { // B
S = bw; sx = bx; sy = by + bh - S;
bh -= S;
}
// Terminate layer scaling once pixel fractions drift invisibly short
if (S < 0.5) break;
// Draw perfect square border
ctx.strokeRect(sx, sy, S, S);
// Draw inward perfectly shaped Quarter Arc component connecting opposite ends
let arc = cw ? arcs.CW[dir] : arcs.CCW[dir];
ctx.beginPath();
ctx.arc(sx + arc.cx * S, sy + arc.cy * S, S, arc.start, arc.end, !cw);
ctx.stroke();
}
return canvas;
}
Apply Changes