You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, platformPreset = "custom", customWidth = 800, customHeight = 600, aspectRatioMode = "fit") {
// Ensure the image is loaded if it's an HTMLImageElement
if (originalImg instanceof HTMLImageElement && !originalImg.complete) {
try {
await new Promise((resolve, reject) => {
originalImg.onload = resolve;
originalImg.onerror = (err) => reject(new Error("Image loading failed: " + err));
// Handle cases where src might not be set or image already errored
if (originalImg.src && originalImg.naturalWidth === 0 && originalImg.naturalHeight === 0 && !originalImg.onerror) {
// This can happen if the image errored before an error handler was attached,
// or if onload/onerror won't fire for other reasons.
// It's a bit of a tricky edge case.
// For now, we assume onload/onerror will fire if not complete.
} else if (!originalImg.src) {
reject(new Error("Image source is not set."));
}
});
} catch (error) {
console.error("Error ensuring image is loaded:", error);
// Create an empty (or error-state) canvas as a fallback
const errorCanvas = document.createElement('canvas');
errorCanvas.width = Number(customWidth) || 800;
errorCanvas.height = Number(customHeight) || 600;
const errorCtx = errorCanvas.getContext('2d');
errorCtx.fillStyle = '#eee';
errorCtx.fillRect(0, 0, errorCanvas.width, errorCanvas.height);
errorCtx.fillStyle = '#000';
errorCtx.textAlign = 'center';
errorCtx.fillText('Error loading image', errorCanvas.width / 2, errorCanvas.height / 2);
return errorCanvas;
}
}
const PRESETS = {
"custom": { width: null, height: null }, // Indicates use of customWidth/customHeight
"facebook_profile": { width: 180, height: 180 },
"facebook_cover": { width: 851, height: 315 },
"facebook_post": { width: 1200, height: 630 }, // Recommended landscape
"facebook_square_post": { width: 1080, height: 1080 },
"facebook_story": { width: 1080, height: 1920 },
"instagram_profile": { width: 320, height: 320 },
"instagram_square": { width: 1080, height: 1080 },
"instagram_portrait": { width: 1080, height: 1350 },
"instagram_landscape": { width: 1080, height: 566 },
"instagram_story": { width: 1080, height: 1920 },
"twitter_profile": { width: 400, height: 400 }, // X (formerly Twitter)
"twitter_header": { width: 1500, height: 500 },
"twitter_post": { width: 1600, height: 900 }, // 16:9 aspect ratio
"twitter_square_post": { width: 1080, height: 1080 },
"linkedin_profile": { width: 400, height: 400 },
"linkedin_cover": { width: 1584, height: 396 },
"linkedin_post": { width: 1200, height: 627 }, // For shared links/articles
"linkedin_square_post": { width: 1200, height: 1200 },
"pinterest_profile": { width: 165, height: 165 },
"pinterest_pin": { width: 1000, height: 1500 }, // Ideal 2:3 aspect ratio
"pinterest_square_pin": { width: 1000, height: 1000 },
"youtube_profile": { width: 800, height: 800 }, // Channel icon (uploads as square)
"youtube_thumbnail": { width: 1280, height: 720 }, // Video thumbnail (16:9)
"youtube_channel_art": { width: 2560, height: 1440 }, // Banner (full, safe areas vary)
"tiktok_profile": { width: 200, height: 200 },
"tiktok_video": { width: 1080, height: 1920 } // Same as Instagram/Facebook Stories
};
let targetWidth, targetHeight;
const selectedPreset = PRESETS[platformPreset];
if (platformPreset === "custom" || !selectedPreset) {
targetWidth = Number(customWidth);
targetHeight = Number(customHeight);
if (isNaN(targetWidth) || targetWidth <= 0) {
console.warn(`Invalid customWidth: "${customWidth}". Defaulting to 800.`);
targetWidth = 800;
}
if (isNaN(targetHeight) || targetHeight <= 0) {
console.warn(`Invalid customHeight: "${customHeight}". Defaulting to 600.`);
targetHeight = 600;
}
} else {
targetWidth = selectedPreset.width;
targetHeight = selectedPreset.height;
}
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = targetWidth;
canvas.height = targetHeight;
let srcWidth = originalImg.naturalWidth;
let srcHeight = originalImg.naturalHeight;
// Fallback for other types of CanvasImageSource or if naturalWidth/Height are 0
if (!srcWidth || srcWidth === 0) {
srcWidth = originalImg.width;
}
if (!srcHeight || srcHeight === 0) {
srcHeight = originalImg.height;
}
// Specific check for video elements for dimensions, as width/height might be styled
if (originalImg instanceof HTMLVideoElement) {
srcWidth = originalImg.videoWidth;
srcHeight = originalImg.videoHeight;
}
if (!srcWidth || !srcHeight || srcWidth <= 0 || srcHeight <= 0) {
console.error("Original image dimensions are invalid (0 or not determinable). Returning a placeholder canvas.");
ctx.fillStyle = '#cccccc';
ctx.fillRect(0, 0, targetWidth, targetHeight);
ctx.fillStyle = '#555555';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.font = '16px Arial';
ctx.fillText('Invalid Source Image', targetWidth / 2, targetHeight / 2);
return canvas;
}
if (aspectRatioMode === "stretch") {
ctx.drawImage(originalImg, 0, 0, srcWidth, srcHeight, 0, 0, targetWidth, targetHeight);
} else if (aspectRatioMode === "fit") {
const srcAspectRatio = srcWidth / srcHeight;
const targetCanvasAspectRatio = targetWidth / targetHeight;
let drawWidth, drawHeight, offsetX, offsetY;
if (srcAspectRatio > targetCanvasAspectRatio) {
// Source image is wider (in terms of aspect ratio) than the target canvas
drawWidth = targetWidth;
drawHeight = drawWidth / srcAspectRatio;
offsetX = 0;
offsetY = (targetHeight - drawHeight) / 2;
} else {
// Source image is taller (or same aspect ratio) than the target canvas
drawHeight = targetHeight;
drawWidth = drawHeight * srcAspectRatio;
offsetY = 0;
offsetX = (targetWidth - drawWidth) / 2;
}
ctx.drawImage(originalImg, 0, 0, srcWidth, srcHeight, offsetX, offsetY, drawWidth, drawHeight);
} else if (aspectRatioMode === "crop") {
const srcAspectRatio = srcWidth / srcHeight;
const targetCropAspectRatio = targetWidth / targetHeight;
let sx = 0, sy = 0, sCropWidth = srcWidth, sCropHeight = srcHeight;
if (srcAspectRatio > targetCropAspectRatio) {
// Source is wider than target aspect ratio, crop sides from source
sCropWidth = srcHeight * targetCropAspectRatio;
sx = (srcWidth - sCropWidth) / 2;
} else if (srcAspectRatio < targetCropAspectRatio) {
// Source is taller than target aspect ratio, crop top/bottom from source
sCropHeight = srcWidth / targetCropAspectRatio;
sy = (srcHeight - sCropHeight) / 2;
}
// If aspect ratios match, no cropping of source content needed (sx, sy, sCropWidth, sCropHeight remain full source)
ctx.drawImage(originalImg, sx, sy, sCropWidth, sCropHeight, 0, 0, targetWidth, targetHeight);
} else {
// Fallback for unknown aspectRatioMode, treat as "fit"
if (aspectRatioMode !== "fit") { // Avoid double warning if it was "fit" originally
console.warn(`Invalid aspectRatioMode: "${aspectRatioMode}". Defaulting to "fit".`);
}
const srcAspectRatio = srcWidth / srcHeight;
const targetCanvasAspectRatio = targetWidth / targetHeight;
let drawWidth, drawHeight, offsetX, offsetY;
if (srcAspectRatio > targetCanvasAspectRatio) {
drawWidth = targetWidth;
drawHeight = drawWidth / srcAspectRatio;
offsetX = 0;
offsetY = (targetHeight - drawHeight) / 2;
} else {
drawHeight = targetHeight;
drawWidth = drawHeight * srcAspectRatio;
offsetY = 0;
offsetX = (targetWidth - drawWidth) / 2;
}
ctx.drawImage(originalImg, 0, 0, srcWidth, srcHeight, offsetX, offsetY, drawWidth, drawHeight);
}
return canvas;
}
Apply Changes