Please bookmark this page to avoid losing your image tool!

Photo Calendar Creator

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
You can edit the below JavaScript code to customize the image tool.
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;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

Photo Calendar Creator is an online tool that enables users to design customized photo calendars. By uploading an image and selecting specific parameters such as the year, month, font styles, and colors, users can create visually appealing calendars that integrate personal images alongside calendar dates. This tool is ideal for personal use, as well as for creating unique gifts, promotional materials, or event-related calendars for businesses and organizations.

Leave a Reply

Your email address will not be published. Required fields are marked *