You can edit the below JavaScript code to customize the image tool.
async function processImage(originalImg, shape = "rectangle", frameColor = "black", frameWidth = 10, starPoints = 5, starInnerRadiusRatio = 0.5) {
const canvas = document.createElement('canvas');
const W = originalImg.width;
const H = originalImg.height;
canvas.width = W;
canvas.height = H;
const ctx = canvas.getContext('2d');
// If frameWidth is zero or negative, no frame is applied.
// Draw the original image onto the canvas and return.
if (frameWidth <= 0) {
ctx.drawImage(originalImg, 0, 0, W, H);
return canvas;
}
// Helper function to define the shape path.
// The path represents the centerline for the frame's stroke.
// The bounding box for this centerline path is defined by _x, _y, _w, _h.
function defineShapePath() {
ctx.beginPath();
// availableX, availableY, availableWidth, availableHeight for the shape's centerline
const _x = frameWidth / 2;
const _y = frameWidth / 2;
const _w = W - frameWidth;
const _h = H - frameWidth;
// If the available space for the shape path is non-positive, a frame cannot be drawn meaningfully.
if (_w <= 0 || _h <= 0) {
return false; // Indicate path could not be defined
}
switch (shape.toLowerCase()) {
case "circle": {
const centerX = _x + _w / 2;
const centerY = _y + _h / 2;
const radius = Math.min(_w, _h) / 2;
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
break;
}
case "ellipse": {
const centerX = _x + _w / 2;
const centerY = _y + _h / 2;
const radiusX = _w / 2;
const radiusY = _h / 2;
ctx.ellipse(centerX, centerY, radiusX, radiusY, 0, 0, 2 * Math.PI);
break;
}
case "star": {
const centerX = _x + _w / 2;
const centerY = _y + _h / 2;
const outerRadius = Math.min(_w, _h) / 2;
// Clamp innerRadiusRatio to prevent degenerate shapes or inversion
const clampedInnerRadiusRatio = Math.max(0.1, Math.min(1, starInnerRadiusRatio));
const innerRadius = outerRadius * clampedInnerRadiusRatio;
// Ensure star has at least 3 points
const numEffectivePoints = Math.max(3, Math.floor(starPoints));
for (let i = 0; i < numEffectivePoints * 2; i++) {
// Angle calculations to create points of the star
const angle = (Math.PI / numEffectivePoints) * i - (Math.PI / 2); // Start from top
const r = (i % 2 === 0) ? outerRadius : innerRadius; // Alternate between outer and inner radius
const currentX = centerX + r * Math.cos(angle);
const currentY = centerY + r * Math.sin(angle);
if (i === 0) {
ctx.moveTo(currentX, currentY);
} else {
ctx.lineTo(currentX, currentY);
}
}
ctx.closePath(); // Close the path to connect the last point to the first
break;
}
case "heart": {
// Defines a heart shape using Bezier curves within the bounding box _x, _y, _w, _h
const midX = _x + _w / 2; // Center X for symmetry
const topIndentY = _y + _h * 0.25; // Y-coordinate of the top indent of the heart
const topLobeY = _y; // Y-coordinate for the peak of the lobes (top of bounding box)
const sideControlY = _y + _h * 0.60; // Y-coordinate for control points defining the curve of the sides
const bottomTipY = _y + _h; // Y-coordinate of the bottom tip of the heart
// X-coordinates for control points, defining the width and curve of lobes
const leftLobeControlX = _x + _w * 0.25;
const rightLobeControlX = _x + _w * 0.75;
const leftEdgeControlX = _x;
const rightEdgeControlX = _x + _w;
ctx.moveTo(midX, topIndentY); // Start at the top indent
// Draw left lobe: from top indent, curve out and down to bottom tip
ctx.bezierCurveTo(leftLobeControlX, topLobeY, leftEdgeControlX, sideControlY, midX, bottomTipY);
// Draw right lobe: from bottom tip, curve out and up back to top indent
ctx.bezierCurveTo(rightEdgeControlX, sideControlY, rightLobeControlX, topLobeY, midX, topIndentY);
ctx.closePath();
break;
}
case "rectangle":
default: { // Default to rectangle if shape is unknown or "rectangle"
ctx.rect(_x, _y, _w, _h);
break;
}
}
return true; // Path successfully defined
}
// Attempt to define the shape path
const pathDefined = defineShapePath();
// If path could not be defined (e.g., image too small for frameWidth),
// draw original image without frame and return.
if (!pathDefined) {
console.warn("Shape could not be drawn, possibly due to small image dimensions relative to frameWidth. Drawing original image without frame.");
ctx.drawImage(originalImg, 0, 0, W, H);
return canvas;
}
// Configure and draw the frame stroke
ctx.strokeStyle = frameColor;
ctx.lineWidth = frameWidth;
ctx.stroke(); // Stroke the defined path
// Prepare to clip the image to the shape
ctx.save(); // Save current canvas state
ctx.clip(); // Clip drawing to the current path. Image will be drawn under the inner half of the stroke.
// Calculate dimensions to draw the image to "cover" the clipped area, maintaining aspect ratio.
// Source (originalImg) dimensions
let sx = 0, sy = 0, sw = originalImg.width, sh = originalImg.height;
// Destination (canvas) dimensions for drawing the image
let dx = 0, dy = 0, dw = W, dh = H;
const imgAspect = originalImg.width / originalImg.height;
const canvasAspect = W / H; // The overall canvas serves as the target area for the "cover" calculation.
if (imgAspect > canvasAspect) { // Image is wider than canvas aspect ratio (needs to be cropped left/right)
dh = H; // Set draw height to canvas height
dw = H * imgAspect; // Calculate proportional width
dx = (W - dw) / 2; // Center horizontally
dy = 0;
} else { // Image is taller or same aspect ratio (needs to be cropped top/bottom)
dw = W; // Set draw width to canvas width
dh = W / imgAspect; // Calculate proportional height
dx = 0;
dy = (H - dh) / 2; // Center vertically
}
// Draw the image, it will be clipped by the path
ctx.drawImage(originalImg, sx, sy, sw, sh, dx, dy, dw, dh);
ctx.restore(); // Restore canvas state to remove clipping
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 Custom-shaped Frame Adder is a versatile online tool that allows users to add decorative frames to their images in various custom shapes, such as rectangles, circles, stars, hearts, and ellipses. Users can customize the frame’s color and width to enhance the visual appeal of their images. This tool is ideal for personalizing photos for social media, creating unique greeting cards, or adding a creative touch to digital artwork. It caters to users looking to make their images stand out with custom framing options.