You can edit the below JavaScript code to customize the image tool.
function processImage(
originalImg,
blurAmount = 10,
centerXPercent = 50,
centerYPercent = 50,
focusRadiusPercent = 25,
highlightThreshold = 220,
highlightSize = 15,
highlightShape = "circle"
) {
// Helper function for drawing hexagon
// Using arrow function syntax for brevity and consistent `this` (though not used here)
const _drawHexagon = (context, x, y, radius) => {
context.beginPath();
for (let i = 0; i < 6; i++) {
// Angle for flat top hexagon (common for aperture shapes)
const angle = (Math.PI / 3) * i + Math.PI / 6;
const hx = x + radius * Math.cos(angle);
const hy = y + radius * Math.sin(angle);
if (i === 0) {
context.moveTo(hx, hy);
} else {
context.lineTo(hx, hy);
}
}
context.closePath();
context.fill();
};
// --- Parameter Validation and Type Casting ---
let numBlurAmount = Number(blurAmount);
let numCenterXPercent = Number(centerXPercent);
let numCenterYPercent = Number(centerYPercent);
let numFocusRadiusPercent = Number(focusRadiusPercent);
let numHighlightThreshold = Number(highlightThreshold);
let numHighlightSize = Number(highlightSize);
let strHighlightShape = String(highlightShape).toLowerCase();
// Assign defaults if parsing failed or values are unreasonable
if (isNaN(numBlurAmount) || numBlurAmount < 0) numBlurAmount = 10;
if (isNaN(numCenterXPercent) || numCenterXPercent < 0 || numCenterXPercent > 100) numCenterXPercent = 50;
if (isNaN(numCenterYPercent) || numCenterYPercent < 0 || numCenterYPercent > 100) numCenterYPercent = 50;
if (isNaN(numFocusRadiusPercent) || numFocusRadiusPercent < 0 || numFocusRadiusPercent > 100) numFocusRadiusPercent = 25;
if (isNaN(numHighlightThreshold) || numHighlightThreshold < 0 || numHighlightThreshold > 255) numHighlightThreshold = 220;
if (isNaN(numHighlightSize) || numHighlightSize <= 0) numHighlightSize = 15;
if (!['circle', 'hexagon'].includes(strHighlightShape)) strHighlightShape = 'circle';
// --- Canvas Setup ---
const outputCanvas = document.createElement('canvas');
const ctx = outputCanvas.getContext('2d');
const w = originalImg.naturalWidth || originalImg.width;
const h = originalImg.naturalHeight || originalImg.height;
if (w === 0 || h === 0) {
console.warn("Image dimensions are zero. Returning empty canvas.");
outputCanvas.width = 0;
outputCanvas.height = 0;
return outputCanvas;
}
outputCanvas.width = w;
outputCanvas.height = h;
// Calculate focus area parameters in pixels
const focusX = (numCenterXPercent / 100) * w;
const focusY = (numCenterYPercent / 100) * h;
const minDimension = Math.min(w, h);
// Radius percent is relative to half of the smaller dimension, so 100% makes diameter = minDimension
const actualFocusRadius = (numFocusRadiusPercent / 100) * (minDimension / 2);
let blurredImageCanvas = null; // To store the purely blurred version for highlight detection
// --- Step 1: Draw Base Image (Blurred or Original) ---
if (numBlurAmount > 0) {
// Create a temporary canvas to hold the blurred image.
// This is crucial because ctx.filter is a live effect, and for getImageData,
// we need the explicit pixel values of the blurred image.
blurredImageCanvas = document.createElement('canvas');
blurredImageCanvas.width = w;
blurredImageCanvas.height = h;
const blurredCtx = blurredImageCanvas.getContext('2d');
blurredCtx.filter = `blur(${numBlurAmount}px)`;
blurredCtx.drawImage(originalImg, 0, 0, w, h);
blurredCtx.filter = 'none'; // Important to remove filter after drawing
// Draw this pre-blurred image onto the main output canvas
ctx.drawImage(blurredImageCanvas, 0, 0, w, h);
} else {
// No blur, draw original image directly to output
ctx.drawImage(originalImg, 0, 0, w, h);
}
// --- Step 2: Detect and Draw Bokeh Highlights ---
// Highlights are drawn if blur is applied, size > 0, and threshold is in a usable range (<255 for denominator).
if (numBlurAmount > 0 && blurredImageCanvas && numHighlightSize > 0 && numHighlightThreshold < 255) {
let imageData;
try {
// Get image data from the canvas that contains the definitive blurred image
const sourceCtx = blurredImageCanvas.getContext('2d');
imageData = sourceCtx.getImageData(0, 0, w, h);
} catch (e) {
console.warn("Could not get image data for highlights (e.g., CORS issue). Highlights skipped.", e);
imageData = null;
}
if (imageData) {
const data = imageData.data;
// Iterate with a step related to highlight size for performance and visual spacing
const step = Math.max(1, Math.floor(numHighlightSize / 2) || 1);
for (let y = 0; y < h; y += step) {
for (let x = 0; x < w; x += step) {
const i = (y * w + x) * 4; // Pixel index
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
// const a = data[i + 3]; // Alpha of source pixel, not used for brightness
const brightness = (r + g + b) / 3; // Simple average brightness
if (brightness > numHighlightThreshold) {
const dx = x - focusX;
const dy = y - focusY;
// Check if the highlight point is outside the focus circle
if (dx * dx + dy * dy > actualFocusRadius * actualFocusRadius) {
// Factor based on how much brightness exceeds threshold, normalized
const excessBrightnessFactor = Math.min((brightness - numHighlightThreshold) / (255 - numHighlightThreshold), 1);
// Modulate alpha of highlights: brighter points are more opaque
const baseAlpha = 0.15;
const finalAlpha = Math.min(baseAlpha + excessBrightnessFactor * 0.4, 0.7); // Max alpha ~0.55, capped further by Math.min
ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${finalAlpha})`;
if (strHighlightShape === 'hexagon') {
_drawHexagon(ctx, x, y, numHighlightSize);
} else { // Default to circle
ctx.beginPath();
ctx.arc(x, y, numHighlightSize, 0, Math.PI * 2);
ctx.fill();
}
}
}
}
}
}
}
// --- Step 3: Draw the Sharp, Focused Area on Top ---
// This reveals the original image within the defined focus circle.
ctx.save(); // Save current state (which includes the blurred image with highlights)
ctx.beginPath();
ctx.arc(focusX, focusY, actualFocusRadius, 0, Math.PI * 2);
ctx.clip(); // Set the circular clipping path
// Draw the original, sharp image. It will only be visible within the clip path.
ctx.drawImage(originalImg, 0, 0, w, h);
ctx.restore(); // Remove clipping path and restore previous canvas state
return outputCanvas;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Image Bokeh Filter Application allows users to enhance their images by applying a bokeh effect, which creates a visually appealing blur around a focused area. Users can adjust parameters such as blur strength, focus area position, focus radius, and highlight characteristics, including shape and size. This tool is useful for photographers and graphic designers looking to emphasize subjects in their images, create artistic effects, or enhance the aesthetic quality of photos for social media, presentations, or print. By isolating and highlighting specific parts of an image while softening the background, it adds depth and dimension to visual compositions.