You can edit the below JavaScript code to customize the image tool.
async function processImage(originalImg, overlayImgSrc = "", blendMode = "overlay", opacity = 0.5, overlayX = 0, overlayY = 0, overlayWidthStr = "original", overlayHeightStr = "original") {
// Helper function to ensure an image element is loaded
async function ensureImageLoaded(imgObject, imgSrcDebugName = "Image") {
return new Promise((resolve, reject) => {
if (!imgObject || typeof imgObject.tagName !== 'string' || imgObject.tagName.toLowerCase() !== 'img') {
reject(new Error(`${imgSrcDebugName} is not a valid HTMLImageElement.`));
return;
}
if (imgObject.complete && imgObject.naturalWidth !== 0) {
resolve(imgObject);
return;
}
if (!imgObject.src) {
// If src is not set, it might be that the Image object was created but src never assigned.
// Or it could be an 'img' tag from DOM without a src.
// Check if it has a pending src to be loaded (e.g. if src was set but execution is here before events fire)
// For this function, originalImg is passed in, so we rely on its state.
// If naturalWidth is 0 and not complete, and no src, it's unrecoverable.
reject(new Error(`${imgSrcDebugName} has no 'src' or is not a loadable image.`));
return;
}
const loadHandler = () => {
cleanup();
if (imgObject.naturalWidth === 0) {
reject(new Error(`${imgSrcDebugName} loaded but has zero dimensions.`));
} else {
resolve(imgObject);
}
};
const errorHandler = (errEvent) => {
cleanup();
reject(new Error(`${imgSrcDebugName} failed to load from src '${imgObject.src}'. Error type: ${errEvent.type}`));
};
const abortHandler = () => {
cleanup();
reject(new Error(`${imgSrcDebugName} loading aborted for src '${imgObject.src}'.`));
};
function cleanup() {
imgObject.removeEventListener('load', loadHandler);
imgObject.removeEventListener('error', errorHandler);
imgObject.removeEventListener('abort', abortHandler);
}
imgObject.addEventListener('load', loadHandler);
imgObject.addEventListener('error', errorHandler);
imgObject.addEventListener('abort', abortHandler);
// If the image is already in a broken state but 'complete' is true (e.g. src was invalid)
if (imgObject.complete && imgObject.naturalWidth === 0) {
errorHandler({type: "Already broken"}); // Simulate error to trigger rejection
}
});
}
try {
await ensureImageLoaded(originalImg, "Original image");
} catch (error) {
console.error("Error with original image:", error.message);
const errorCanvas = document.createElement('canvas');
errorCanvas.width = 100;
errorCanvas.height = 30;
const errCtx = errorCanvas.getContext('2d');
if (errCtx) {
errCtx.font = "10px sans-serif";
errCtx.fillStyle = "red";
errCtx.fillText("Original image error", 5, 15);
}
return errorCanvas;
}
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = originalImg.naturalWidth;
canvas.height = originalImg.naturalHeight;
if (canvas.width === 0 || canvas.height === 0) {
console.error("Original image has zero width or height after ensuring load. Cannot process.");
// Return the 0x0 canvas as per current setup, or an error canvas like above
return canvas;
}
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
if (!overlayImgSrc || typeof overlayImgSrc !== 'string' || overlayImgSrc.trim() === "") {
// No overlay image source provided, return canvas with only the original image
return canvas;
}
try {
const overlayImage = await new Promise((resolve, reject) => {
const img = new Image();
try {
// Attempt to resolve overlayImgSrc relative to document base URL if it's a relative path
// This helps in determining if it's cross-origin for http/https URLs
const overlayUrl = new URL(overlayImgSrc, (typeof document !== 'undefined' && document.baseURI) || window.location.href);
if (overlayUrl.protocol.startsWith('http') && overlayUrl.origin !== window.location.origin) {
img.crossOrigin = 'Anonymous';
}
} catch (e) {
// This can happen if overlayImgSrc is not a valid URL string (e.g. "foo")
// or uses a scheme not resolvable with a base (e.g. "data:", "blob:").
// For "data:" and "blob:" URLs, crossOrigin is not needed or applicable in the same way.
// Silently ignore error, means crossOrigin won't be set, which is fine for these cases.
}
img.onload = () => resolve(img);
img.onerror = (errEvent) => reject(new Error(`Failed to load overlay image. Status: ${errEvent.type}`));
img.onabort = () => reject(new Error(`Overlay image loading aborted.`));
img.src = overlayImgSrc;
});
if (overlayImage.naturalWidth === 0 || overlayImage.naturalHeight === 0) {
console.warn("Overlay image loaded but has zero width or height. Skipping overlay.");
return canvas; // Return canvas with original image only
}
let ow, oh;
const finalOverlayX = typeof overlayX === 'number' ? overlayX : parseFloat(String(overlayX));
const finalOverlayY = typeof overlayY === 'number' ? overlayY : parseFloat(String(overlayY));
if (isNaN(finalOverlayX) || isNaN(finalOverlayY)) {
console.warn(`Invalid overlayX ("${overlayX}") or overlayY ("${overlayY}"). Defaulting to (0,0).`);
ctx.drawImage(overlayImage, 0, 0, ow, oh); // This will use undefined ow,oh if logic below fails
}
// Calculate overlay width
const parsedOverlayWidth = parseFloat(overlayWidthStr);
if (overlayWidthStr === "original") {
ow = canvas.width;
} else if (overlayWidthStr === "auto" || isNaN(parsedOverlayWidth) || parsedOverlayWidth <= 0) {
ow = overlayImage.naturalWidth;
} else {
ow = parsedOverlayWidth;
}
// Calculate overlay height
const parsedOverlayHeight = parseFloat(overlayHeightStr);
if (overlayHeightStr === "original") {
oh = canvas.height;
} else if (overlayHeightStr === "auto" || isNaN(parsedOverlayHeight) || parsedOverlayHeight <= 0) {
oh = overlayImage.naturalHeight;
} else {
oh = parsedOverlayHeight;
}
const validBlendModes = [
'source-over', 'source-in', 'source-out', 'source-atop',
'destination-over', 'destination-in', 'destination-out', 'destination-atop',
'lighter', 'copy', 'xor', 'multiply', 'screen', 'overlay', 'darken',
'lighten', 'color-dodge', 'color-burn', 'hard-light', 'soft-light',
'difference', 'exclusion', 'hue', 'saturation', 'color', 'luminosity'
];
let currentBlendMode = "overlay"; // Default blend mode
if (validBlendModes.includes(blendMode)) {
currentBlendMode = blendMode;
} else {
console.warn(`Invalid blend mode: "${blendMode}". Defaulting to "overlay".`);
}
ctx.globalCompositeOperation = currentBlendMode;
const parsedOpacity = typeof opacity === 'number' ? opacity : parseFloat(String(opacity));
let finalOpacity = 0.5; // Default opacity
if (!isNaN(parsedOpacity)) {
finalOpacity = Math.max(0, Math.min(1, parsedOpacity));
} else {
console.warn(`Invalid opacity: "${opacity}". Defaulting to 0.5.`);
}
ctx.globalAlpha = finalOpacity;
// Use the potentially corrected finalOverlayX/Y from above check
const xToDraw = isNaN(finalOverlayX) ? 0 : finalOverlayX;
const yToDraw = isNaN(finalOverlayY) ? 0 : finalOverlayY;
ctx.drawImage(overlayImage, xToDraw, yToDraw, ow, oh);
// Reset context properties to defaults
ctx.globalCompositeOperation = 'source-over';
ctx.globalAlpha = 1.0;
} catch (error) {
console.error("Error processing overlay image:", error.message);
// Original image is already on canvas, so return it as is if overlay fails.
}
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 Background Blending Adder is a versatile online tool designed to overlay one image on top of another, allowing users to blend the two images using various blending modes and adjustable opacity levels. This tool can be useful for graphic designers, marketers, and social media managers who want to create visually appealing images by combining graphics, logos, or backgrounds. Users can specify the position, size, and transparency of the overlay image to achieve their desired artistic effects, making it ideal for creating promotional materials, social media posts, or artwork enhancements.