You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, yearParam, monthParam, fontFamilyParam,
headerBgColorParam, headerTextColorParam,
daysOfWeekBgColorParam, daysOfWeekTextColorParam,
dateCellBgColorParam, dateCellTextColorParam,
todayCellBgColorParam, todayCellTextColorParam,
canvasWidthParam, gridLineColorParam) {
// --- 1. Constants and Parameter Defaults ---
const MONTH_NAMES = ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"];
const DAY_NAMES = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
const currentDate = new Date();
const year = yearParam !== undefined ? Number(yearParam) : currentDate.getFullYear();
const month = monthParam !== undefined ? Number(monthParam) : currentDate.getMonth() + 1; // month is 1-12
const fontFamily = fontFamilyParam || 'Arial, sans-serif';
// Calendar Section Colors
const headerBgColor = headerBgColorParam || '#337AB7'; // Dark blueish
const headerTextColor = headerTextColorParam || '#FFFFFF'; // White
const daysOfWeekBgColor = daysOfWeekBgColorParam || '#F5F5F5'; // Light gray
const daysOfWeekTextColor = daysOfWeekTextColorParam || '#333333'; // Dark gray
const dateCellBgColor = dateCellBgColorParam || '#FFFFFF'; // White
const dateCellTextColor = dateCellTextColorParam || '#000000'; // Black
const todayCellBgColor = todayCellBgColorParam || '#FFF3CD'; // Light yellow (like Bootstrap's warning)
const todayCellTextColor = todayCellTextColorParam || '#856404'; // Dark yellow/brown (Bootstrap's warning text)
const gridLineColor = gridLineColorParam || '#DDDDDD'; // Light gray for borders
const canvasWidth = canvasWidthParam !== undefined ? Number(canvasWidthParam) : 800;
// --- 2. Canvas Setup ---
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = canvasWidth;
// --- 3. Calendar Logic ---
// month is 1-12, Date object needs 0-11 for month index
const firstDayOfMonth = new Date(year, month - 1, 1).getDay(); // 0 (Sun) to 6 (Sat)
const daysInMonth = new Date(year, month, 0).getDate(); // Correctly gets days in 'month' (1-12)
// --- 4. Layout Dimensions ---
// Image part: height is 60% of canvas width. Can be adjusted.
const imageToCanvasWidthRatio = 0.6;
const imageHeight = canvasWidth * imageToCanvasWidthRatio;
// Calendar parts heights: responsive to canvasWidth, with min values
const calendarHeaderHeight = Math.max(50, canvasWidth * 0.075); // For "Month Year"
const daysOfWeekHeaderHeight = Math.max(30, canvasWidth * 0.05); // For "Sun, Mon, ..."
const numCalendarGridRows = Math.ceil((firstDayOfMonth + daysInMonth) / 7);
const dateCellHeight = Math.max(50, canvasWidth * 0.075); // For individual date cells
const dateGridHeight = numCalendarGridRows * dateCellHeight;
canvas.height = imageHeight + calendarHeaderHeight + daysOfWeekHeaderHeight + dateGridHeight;
// --- 5. Draw Image (Covering the top part) ---
// Target dimensions for image part on canvas
const imgPartTargetWidth = canvas.width;
const imgPartTargetHeight = imageHeight;
// Calculate how to crop/scale image to "cover" the target area
let sx = 0, sy = 0, sWidth = originalImg.width, sHeight = originalImg.height;
if (originalImg.width > 0 && originalImg.height > 0) { // Check for valid image dimensions
const imgAspectRatio = originalImg.width / originalImg.height;
const targetAspectRatio = imgPartTargetWidth / imgPartTargetHeight;
if (imgAspectRatio > targetAspectRatio) {
// Image is wider than target area, crop left/right
sHeight = originalImg.height;
sWidth = originalImg.height * targetAspectRatio;
sx = (originalImg.width - sWidth) / 2;
} else {
// Image is taller or same aspect as target area, crop top/bottom
sWidth = originalImg.width;
sHeight = originalImg.width / targetAspectRatio;
sy = (originalImg.height - sHeight) / 2;
}
ctx.drawImage(originalImg, sx, sy, sWidth, sHeight, 0, 0, imgPartTargetWidth, imgPartTargetHeight);
} else {
// Fallback: draw a placeholder if image has no dimensions (e.g., not loaded or invalid)
ctx.fillStyle = '#CCCCCC'; // Light gray placeholder
ctx.fillRect(0, 0, imgPartTargetWidth, imgPartTargetHeight);
ctx.fillStyle = '#FFFFFF';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
const placeholderFontSize = Math.min(imgPartTargetWidth, imgPartTargetHeight) * 0.1;
ctx.font = `bold ${placeholderFontSize}px ${fontFamily}`;
ctx.fillText('Image Error', imgPartTargetWidth / 2, imgPartTargetHeight / 2);
}
let currentYOffset = imageHeight; // Start drawing calendar below the image
// --- 6. Draw Calendar Header (Month Year) ---
ctx.fillStyle = headerBgColor;
ctx.fillRect(0, currentYOffset, canvas.width, calendarHeaderHeight);
ctx.fillStyle = headerTextColor;
const calendarHeaderFontSize = calendarHeaderHeight * 0.5;
ctx.font = `bold ${calendarHeaderFontSize}px ${fontFamily}`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
const monthName = MONTH_NAMES[month - 1];
ctx.fillText(`${monthName} ${year}`, canvas.width / 2, currentYOffset + calendarHeaderHeight / 2);
currentYOffset += calendarHeaderHeight;
// --- 7. Draw Days of Week Header ---
const dayCellWidth = canvas.width / 7;
ctx.fillStyle = daysOfWeekBgColor;
ctx.fillRect(0, currentYOffset, canvas.width, daysOfWeekHeaderHeight);
ctx.fillStyle = daysOfWeekTextColor;
const daysOfWeekFontSize = daysOfWeekHeaderHeight * 0.45;
ctx.font = `bold ${daysOfWeekFontSize}px ${fontFamily}`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
for (let i = 0; i < DAY_NAMES.length; i++) {
ctx.fillText(DAY_NAMES[i], i * dayCellWidth + dayCellWidth / 2, currentYOffset + daysOfWeekHeaderHeight / 2);
}
// Draw grid lines for the days of week header
ctx.strokeStyle = gridLineColor;
ctx.lineWidth = 1;
for (let i = 0; i <= 7; i++) { // Vertical lines including edges
ctx.beginPath();
ctx.moveTo(i * dayCellWidth, currentYOffset);
ctx.lineTo(i * dayCellWidth, currentYOffset + daysOfWeekHeaderHeight);
ctx.stroke();
}
ctx.beginPath(); // Horizontal line below day names
ctx.moveTo(0, currentYOffset + daysOfWeekHeaderHeight);
ctx.lineTo(canvas.width, currentYOffset + daysOfWeekHeaderHeight);
ctx.stroke();
currentYOffset += daysOfWeekHeaderHeight;
// --- 8. Draw Date Grid ---
let dayCounter = 1;
const dateCellFontSize = dateCellHeight * 0.35;
for (let r = 0; r < numCalendarGridRows; r++) { // Rows
for (let c = 0; c < 7; c++) { // Columns (days of week)
const cellX = c * dayCellWidth;
const cellY = currentYOffset + r * dateCellHeight;
// Check if this cell is for a day of the current month
if ((r === 0 && c < firstDayOfMonth) || dayCounter > daysInMonth) {
// Cell is empty (belongs to previous or next month)
ctx.fillStyle = '#FAFAFA'; // A very light gray for unused cells
ctx.fillRect(cellX, cellY, dayCellWidth, dateCellHeight);
} else {
// Cell is for a day in the current month
const isToday = (currentDate.getFullYear() === year &&
currentDate.getMonth() + 1 === month && // Compare 1-12 month
currentDate.getDate() === dayCounter);
if (isToday) {
ctx.fillStyle = todayCellBgColor;
ctx.fillRect(cellX, cellY, dayCellWidth, dateCellHeight);
ctx.fillStyle = todayCellTextColor;
ctx.font = `bold ${dateCellFontSize}px ${fontFamily}`; // Today's date bold
} else {
ctx.fillStyle = dateCellBgColor;
ctx.fillRect(cellX, cellY, dayCellWidth, dateCellHeight);
ctx.fillStyle = dateCellTextColor;
ctx.font = `${dateCellFontSize}px ${fontFamily}`; // Regular date font
}
ctx.textAlign = 'center';
ctx.textBaseline = 'middle'; // Vertically center text in cell
ctx.fillText(dayCounter.toString(), cellX + dayCellWidth / 2, cellY + dateCellHeight / 2);
dayCounter++;
}
// Draw grid line for each cell
ctx.strokeStyle = gridLineColor;
ctx.lineWidth = 1;
ctx.strokeRect(cellX, cellY, dayCellWidth, dateCellHeight);
}
}
// --- 9. Return Canvas ---
return canvas;
}
Apply Changes