You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(
originalImg,
documentTitle = "ARCHAEOLOGICAL FIND RECORD",
artifactId = "AD-001-XYZ",
objectName = "Ancient Artifact",
discoveryDate = "January 1, 2024",
discoverySite = "Uncharted Territory",
estimatedAge = "Approx. 2000 Years",
researcherName = "Dr. E. L. Cortex",
description = "A remarkable discovery indicating advanced craftsmanship for its era. Further analysis pending examination by experts in the relevant historical and material sciences departments.",
bgColor = "#f5e8c7", // Parchment like
textColor = "#3a2e0b", // Dark brown
accentColor = "#5a4510" // Slightly darker brown for accents
) {
const titleFontName = "IM Fell English SC";
const bodyFontName = "IM Fell English";
const loadFont = async (fontFamily, fontUrl) => {
try {
if (document.fonts && typeof document.fonts.check === 'function' && document.fonts.check(`12px "${fontFamily}"`)) {
return true; // Already loaded or available
}
const fontFace = new FontFace(fontFamily, `url(${fontUrl})`);
await fontFace.load();
document.fonts.add(fontFace);
return true;
} catch (e) {
console.error(`Failed to load font ${fontFamily}:`, e);
return false;
}
};
await Promise.all([
loadFont(titleFontName, "https://fonts.gstatic.com/s/imfellenglishsc/v16/yVT0H4Vd0mBDA2rhohP3428a0cR8KLIg047K.woff2"),
loadFont(bodyFontName, "https://fonts.gstatic.com/s/imfellenglish/v16/Ktk1ALSLW8zR2viiObOffY220jYJ2oIA4Q.woff2")
]);
const isFontAvailable = (fontName) => {
if (!document.fonts || typeof document.fonts.check !== 'function') return false;
return document.fonts.check(`12px "${fontName}"`);
};
const fallbackTitleFontFamily = `"Times New Roman", serif`;
const fallbackBodyFontFamily = `"Times New Roman", serif`;
const titleActualFontFamily = isFontAvailable(titleFontName) ? `"${titleFontName}"` : fallbackTitleFontFamily;
const bodyActualFontFamily = isFontAvailable(bodyFontName) ? `"${bodyFontName}"` : fallbackBodyFontFamily;
const titleFontSize = 36;
const smallFontSize = 16;
const lineSpacingFactor = 1.4;
const fontStyles = {
title: `bold ${titleFontSize}px ${titleActualFontFamily}`,
small: `${smallFontSize}px ${bodyActualFontFamily}`,
smallBold: `bold ${smallFontSize}px ${bodyActualFontFamily}`
};
const tempCanvas = document.createElement('canvas');
const ctx = tempCanvas.getContext('2d');
const fixedWidth = 800;
const padding = 40;
const contentWidth = fixedWidth - 2 * padding;
ctx.textBaseline = 'top';
const drawTextLine = (text, x, y, font, color, align = 'left', maxWidth = contentWidth) => {
ctx.font = font;
ctx.fillStyle = color;
ctx.textAlign = align;
let textX = x;
if (align === 'center') {
textX = fixedWidth / 2;
} else if (align === 'right') {
textX = fixedWidth - padding;
}
ctx.fillText(text, textX, y, maxWidth);
const fontSize = parseInt(font.match(/(\d+)px/)[1], 10);
return y + fontSize * lineSpacingFactor;
};
const wrapTextAndDraw = (text, x, y, maxWidth, font, color) => {
ctx.font = font;
ctx.fillStyle = color;
ctx.textAlign = 'left';
const words = text.split(' ');
let line = '';
let currentTextY = y;
const fontSize = parseInt(font.match(/(\d+)px/)[1], 10);
const lineHeight = fontSize * lineSpacingFactor;
for (let n = 0; n < words.length; n++) {
const testLine = line + words[n] + ' ';
const metrics = ctx.measureText(testLine);
const testWidth = metrics.width;
if (testWidth > maxWidth && line.length > 0) { // Ensure line is not empty before breaking
ctx.fillText(line.trim(), x, currentTextY);
line = words[n] + ' ';
currentTextY += lineHeight;
} else {
line = testLine;
}
}
if (line.trim().length > 0) {
ctx.fillText(line.trim(), x, currentTextY);
}
return currentTextY + lineHeight;
};
const getValueTextLines = (text, maxWidth, font, contextForMeasure) => {
const words = text.split(' ');
const lines = [];
let currentLine = '';
contextForMeasure.font = font;
if (maxWidth <= 0) return [text.trim()];
for (let i = 0; i < words.length; i++) {
let word = words[i];
let testLine = currentLine + word + ' ';
if (contextForMeasure.measureText(testLine).width > maxWidth && currentLine.length > 0) {
lines.push(currentLine.trim());
currentLine = word + ' ';
} else {
currentLine = testLine;
}
}
if (currentLine.trim().length > 0) {
lines.push(currentLine.trim());
}
return lines.length > 0 ? lines : (text.trim() ? [text.trim()] : []); // if text was empty, return empty array
};
const maxImgHeight = 350;
const imgAspectRatio = (originalImg.height > 0 && originalImg.width > 0) ? (originalImg.width / originalImg.height) : 1;
let imgDisplayWidth = Math.min(originalImg.width > 0 ? originalImg.width : (contentWidth * 0.55) , contentWidth * 0.55);
let imgDisplayHeight = imgDisplayWidth / imgAspectRatio;
if (imgDisplayHeight > maxImgHeight) {
imgDisplayHeight = maxImgHeight;
imgDisplayWidth = imgDisplayHeight * imgAspectRatio;
}
if (imgDisplayWidth <= 0 || !isFinite(imgDisplayWidth)) {
imgDisplayWidth = contentWidth * 0.55;
}
if (imgDisplayHeight <= 0 || !isFinite(imgDisplayHeight)) {
imgDisplayHeight = maxImgHeight / 1.5;
}
tempCanvas.width = fixedWidth;
tempCanvas.height = 3000; // Temp large height
ctx.textBaseline = 'top';
ctx.fillStyle = bgColor; // This needs to be on finalCtx later
ctx.fillRect(0, 0, tempCanvas.width, tempCanvas.height); // Effectively clears temp
let currentY = padding;
currentY = drawTextLine(documentTitle, 0, currentY, fontStyles.title, textColor, 'center');
currentY += 10;
const artifactIdLineY = currentY;
ctx.font = fontStyles.small;
ctx.fillStyle = textColor;
ctx.textAlign = 'left';
ctx.fillText(`Artifact ID: ${artifactId}`, padding, artifactIdLineY);
ctx.textAlign = 'right';
ctx.fillText(`Date: ${discoveryDate}`, fixedWidth - padding, artifactIdLineY);
currentY += smallFontSize * lineSpacingFactor + 15;
ctx.strokeStyle = accentColor;
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(padding, currentY);
ctx.lineTo(fixedWidth - padding, currentY);
ctx.stroke();
currentY += 20;
const imgSectionStartY = currentY;
const imgMargin = 20;
const imgBorder = 5;
ctx.fillStyle = "#ccc";
ctx.fillRect(padding - imgBorder, currentY - imgBorder, imgDisplayWidth + 2 * imgBorder, imgDisplayHeight + 2 * imgBorder);
ctx.fillStyle = "#fff";
ctx.fillRect(padding, currentY, imgDisplayWidth, imgDisplayHeight);
if (originalImg.width > 0 && originalImg.height > 0) {
ctx.drawImage(originalImg, padding, currentY, imgDisplayWidth, imgDisplayHeight);
} else {
ctx.font = fontStyles.small;
ctx.fillStyle = textColor;
ctx.textAlign = "center";
ctx.fillText("[Image Unavailable]", padding + imgDisplayWidth/2, currentY + imgDisplayHeight/2 - smallFontSize/2);
}
const imageBottomY = currentY + imgDisplayHeight;
let metadataCurrentY = imgSectionStartY;
const metadataStartX = padding + imgDisplayWidth + imgMargin;
const metadataBlockAvailableWidth = fixedWidth - padding - metadataStartX;
const drawMetadataItem = (label, value) => {
ctx.textAlign = 'left';
ctx.font = fontStyles.smallBold;
ctx.fillStyle = textColor;
ctx.fillText(label, metadataStartX, metadataCurrentY);
const labelWidth = ctx.measureText(label + " ").width;
const valueLines = getValueTextLines(value, metadataBlockAvailableWidth - labelWidth, fontStyles.small, ctx);
let lineYOffset = 0;
const valueLineHeight = smallFontSize * lineSpacingFactor;
ctx.font = fontStyles.small; // Set font for value rendering
for(const line of valueLines) {
ctx.fillText(line, metadataStartX + labelWidth, metadataCurrentY + lineYOffset);
lineYOffset += valueLineHeight;
}
metadataCurrentY += (lineYOffset > 0 ? lineYOffset : valueLineHeight);
metadataCurrentY += 5;
};
if (metadataBlockAvailableWidth > 20) {
drawMetadataItem("Object Name:", objectName);
drawMetadataItem("Est. Age:", estimatedAge);
drawMetadataItem("Site:", discoverySite);
drawMetadataItem("Researcher:", researcherName);
}
currentY = Math.max(imageBottomY, metadataCurrentY) + 20;
currentY = drawTextLine("Description:", padding, currentY, fontStyles.smallBold, textColor, 'left');
currentY += 5;
currentY = wrapTextAndDraw(description, padding, currentY, contentWidth, fontStyles.small, textColor);
const finalHeight = currentY + padding;
const finalCanvas = document.createElement('canvas');
finalCanvas.width = fixedWidth;
finalCanvas.height = finalHeight;
const finalCtx = finalCanvas.getContext('2d');
finalCtx.textBaseline = 'top';
finalCtx.fillStyle = bgColor;
finalCtx.fillRect(0, 0, finalCanvas.width, finalCanvas.height);
const noiseDensityFactor = 70;
const numNoiseParticles = Math.floor((finalCanvas.width * finalCanvas.height / (800*600)) * noiseDensityFactor * 100);
for (let i = 0; i < numNoiseParticles; i++) {
const x = Math.random() * finalCanvas.width;
const y = Math.random() * finalCanvas.height;
const alpha = Math.random() * 0.03 + 0.02;
const shade = Math.random() > 0.5 ? 20 : 40;
finalCtx.fillStyle = `rgba(${shade},${shade},${shade},${alpha})`; // Darker noise for parchment
finalCtx.fillRect(x, y, 1, 1);
}
finalCtx.drawImage(tempCanvas, 0, 0, fixedWidth, finalHeight, 0, 0, fixedWidth, finalHeight);
return finalCanvas;
}
Apply Changes