Source: ui/screenshotController.js

/**
 * @module ScreenshotController
 * @author Radim Brnka
 * @description Screenshot capturing logic.
 */

import {JuliaRenderer} from "../renderers/juliaRenderer";
import {APP_NAME, DEFAULT_CONSOLE_GROUP_COLOR} from "../global/constants";
import {expandComplexToString} from "../global/utils";
import {isJuliaMode} from "./ui";

/**
 * Generates filename based on current timestamp
 * @return {string}
 */
function getFilename() {
    const now = new Date();
    const pad = (n) => String(n).padStart(2, '0');
    return `fractal-${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}_${pad(now.getHours())}-${pad(now.getMinutes())}-${pad(now.getSeconds())}.jpg`;
}

/**
 * Returns watermark text that fits current fractal type and its properties.
 * @param {FractalRenderer} fractalApp
 * @return {string}
 */
function getWatermarkText(fractalApp) {
    const fractalType = isJuliaMode() ? 'Julia' : 'Mandelbrot';

    return `Created by ${APP_NAME} (${fractalType}: ` +
        `p=${expandComplexToString(fractalApp.pan.slice(), 6)}, zoom=${fractalApp.zoom.toFixed(6)}` +
        `${(fractalApp instanceof JuliaRenderer) ? `, c=${expandComplexToString(fractalApp.c)})` : `)`}`;
}

/**
 * Draws rectangle with rounded borders
 * @param {CanvasRenderingContext2D} ctx
 * @param {number} x
 * @param {number} y
 * @param {number} width
 * @param {number} height
 * @param {number} radius
 */
function drawRoundRect(ctx, x, y, width, height, radius) {
    ctx.beginPath();
    ctx.moveTo(x + radius, y);
    ctx.lineTo(x + width - radius, y);
    ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
    ctx.lineTo(x + width, y + height - radius);
    ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
    ctx.lineTo(x + radius, y + height);
    ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
    ctx.lineTo(x, y + radius);
    ctx.quadraticCurveTo(x, y, x + radius, y);
    ctx.closePath();
}

/**
 * Generates screenshot of the canvas, adds watermark and emulates link click to download the file.
 * @param {HTMLCanvasElement} canvas
 * @param {FractalRenderer} fractalApp
 * @param {string} accentColor
 */
export function takeScreenshot(canvas, fractalApp, accentColor) {
    console.groupCollapsed(`%c takeScreenshot`, `color: ${DEFAULT_CONSOLE_GROUP_COLOR}`);

    // Ensure the fractal is fully rendered before taking a screenshot
    fractalApp.draw();

    // Create an offscreen canvas for watermarking
    const offscreenCanvas = document.createElement('canvas');
    offscreenCanvas.width = canvas.width;
    offscreenCanvas.height = canvas.height;
    const ctx = offscreenCanvas.getContext('2d');

    if (!ctx) {
        console.error('Unable to get 2D context for the canvas.');
        return;
    }

    // Copy the fractal canvas content to the offscreen canvas
    ctx.drawImage(canvas, 0, 0);

    // Define the watermark text and style
    let watermarkText = getWatermarkText(fractalApp);
    const fontSize = 12;
    const padding = 6;
    const borderWidth = 1;

    ctx.font = `${fontSize}px sans-serif`;
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';

    // Measure the text width and calculate the rectangle size
    const textWidth = ctx.measureText(watermarkText).width;
    const rectWidth = textWidth + padding * 2 + borderWidth * 2;
    const rectHeight = fontSize + padding * 2 + borderWidth * 2;

    // Position the rectangle in the bottom-right corner
    const x = offscreenCanvas.width - rectWidth - padding;
    const y = offscreenCanvas.height - rectHeight - padding;

    // Draw the semi-transparent black background
    ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
    drawRoundRect(ctx, x, y, rectWidth, rectHeight, 8);  // 10 is the corner radius, adjust as needed
    ctx.fill();

    // Draw the border
    // ctx.strokeStyle = accentColor;
    // ctx.lineWidth = borderWidth;
    // drawRoundRect(ctx, x, y, rectWidth, rectHeight, 8);
    // ctx.stroke();

    // Draw the text centered within the rectangle
    const textX = x + rectWidth / 2;
    const textY = y + rectHeight / 2 + 1;
    ctx.fillStyle = accentColor;
    ctx.fillText(watermarkText, textX, textY);

    // Create a temporary link for downloading the image
    const link = document.createElement('a');

    // Set the download attributes
    link.setAttribute('download', getFilename());
    link.setAttribute('href', offscreenCanvas.toDataURL("image/jpeg", 0.95));
    link.click();

    console.log('Screenshot successfully taken.');
    console.groupEnd();
}