Please bookmark this page to avoid losing your image tool!

Image To Japanese Character Art Converter

(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,
    characterSet = " ・ヽーリハメカサタキヌア字画愛龍鬱", // User-provided string, ordered by visual density (lightest to densest)
    resolutionFactor = 0.07, // Determines block size for sampling: block size = 1/resolutionFactor. Smaller val = coarser.
    fontSize = 10, // Font size of characters in output canvas
    fontFamily = "'MS Mincho', 'Yu Gothic', 'Meiryo', 'Noto Sans JP', 'Hiragino Kaku Gothic ProN', 'sans-serif'",
    invertColorOutput = 0, // 0 for black text on white bg, 1 for white text on black bg
    invertBrightnessMap = 0  // 0 for dark image areas -> dense chars, 1 for light image areas -> dense chars
) {
    // --- 1. Parameter Sanitization ---
    const parsedRF = parseFloat(resolutionFactor);
    resolutionFactor = (isNaN(parsedRF) || parsedRF === 0) ? 0.07 : parsedRF;
    resolutionFactor = Math.max(0.001, Math.min(1, resolutionFactor)); // Clamp to avoid extreme block sizes

    const parsedFontSize = parseInt(fontSize);
    fontSize = isNaN(parsedFontSize) || parsedFontSize <= 0 ? 10 : parsedFontSize;
    fontSize = Math.max(1, fontSize); // Ensure font size is at least 1

    invertColorOutput = (parseInt(invertColorOutput) === 1) ? 1 : 0;
    invertBrightnessMap = (parseInt(invertBrightnessMap) === 1) ? 1 : 0;

    let chars = characterSet.split('');
    if (chars.length === 0) {
        chars = ['?']; // Fallback for empty character set
    }
    const numChars = chars.length;

    // --- 2. Prepare Source Image Data on a Temporary Canvas ---
    // Using naturalWidth/Height for intrinsic dimensions
    const imgWidth = originalImg.naturalWidth || originalImg.width;
    const imgHeight = originalImg.naturalHeight || originalImg.height;

    if (imgWidth === 0 || imgHeight === 0) {
        console.error("Image has no dimensions.");
        const errorCanvas = document.createElement('canvas');
        errorCanvas.width = 200; errorCanvas.height = 30;
        const errCtx = errorCanvas.getContext('2d');
        errCtx.font = "12px Arial"; errCtx.fillStyle = "red";
        errCtx.fillText("Error: Image has no dimensions.", 5, 20);
        return errorCanvas;
    }

    const tempCanvas = document.createElement('canvas');
    tempCanvas.width = imgWidth;
    tempCanvas.height = imgHeight;
    const tempCtx = tempCanvas.getContext('2d', { willReadFrequently: true });

    // Fill with white background first to handle transparency in source image
    // Transparent areas will be treated as "white" for brightness calculation.
    tempCtx.fillStyle = 'white';
    tempCtx.fillRect(0, 0, tempCanvas.width, tempCanvas.height);
    tempCtx.drawImage(originalImg, 0, 0);

    // --- 3. Calculate Output Dimensions ---
    // samplingBlockSize: The width/height of a pixel block in the original image that maps to one character.
    const samplingBlockSize = Math.max(1, Math.floor(1 / resolutionFactor));

    const numCharCols = Math.floor(imgWidth / samplingBlockSize);
    const numCharRows = Math.floor(imgHeight / samplingBlockSize);

    if (numCharCols === 0 || numCharRows === 0) {
        console.error("Output character grid is 0x0. Image too small or resolutionFactor too low for current image size.");
        const errorCanvas = document.createElement('canvas');
        errorCanvas.width = 300; errorCanvas.height = 30;
        const errCtx = errorCanvas.getContext('2d');
        errCtx.font = "12px Arial"; errCtx.fillStyle = "red";
        errCtx.fillText("Error: Output grid is 0x0. Adjust image/resolution.", 5, 20);
        return errorCanvas;
    }

    // --- 4. Prepare Output Canvas ---
    const outputCanvas = document.createElement('canvas');
    // Japanese characters are often full-width (square-ish).
    // Use fontSize for both width and height of the character cell for layout.
    const charCellWidth = fontSize;
    const charCellHeight = fontSize;

    outputCanvas.width = numCharCols * charCellWidth;
    outputCanvas.height = numCharRows * charCellHeight;
    const outCtx = outputCanvas.getContext('2d');

    // --- 5. Set Up Drawing Style on Output Canvas ---
    outCtx.font = `${fontSize}px ${fontFamily}`;
    outCtx.textBaseline = 'middle'; // Align text vertically to the middle of the cell
    outCtx.textAlign = 'center';   // Align text horizontally to the center of the cell

    const bgColor = (invertColorOutput === 1) ? 'black' : 'white';
    const textColor = (invertColorOutput === 1) ? 'white' : 'black';

    outCtx.fillStyle = bgColor;
    outCtx.fillRect(0, 0, outputCanvas.width, outputCanvas.height);
    outCtx.fillStyle = textColor;

    // --- 6. Process Image Blocks and Draw Characters ---
    for (let r = 0; r < numCharRows; r++) { // Current character row
        for (let c = 0; c < numCharCols; c++) { // Current character column
            const imgBlockX = c * samplingBlockSize;
            const imgBlockY = r * samplingBlockSize;
            
            // Ensure block dimensions are within image bounds (especially for last row/col)
            const blockW = Math.min(samplingBlockSize, imgWidth - imgBlockX);
            const blockH = Math.min(samplingBlockSize, imgHeight - imgBlockY);

            if (blockW <= 0 || blockH <= 0) continue; // Should not happen if numCharCols/Rows > 0

            const imageData = tempCtx.getImageData(imgBlockX, imgBlockY, blockW, blockH);
            const data = imageData.data;
            let totalBrightness = 0;
            let pixelCount = 0;

            for (let i = 0; i < data.length; i += 4) {
                const R = data[i];
                const G = data[i + 1];
                const B = data[i + 2];
                // Using standard luminance formula (ITU-R BT.709)
                const brightness = 0.2126 * R + 0.7152 * G + 0.0722 * B; // More perceptually accurate
                // const brightness = 0.299 * R + 0.587 * G + 0.114 * B; // Older standard, also common
                totalBrightness += brightness;
                pixelCount++;
            }

            const avgBrightness = (pixelCount > 0) ? (totalBrightness / pixelCount) : 0; // Range: 0 (black) to 255 (white)
            const normalizedBrightness = avgBrightness / 255; // Range: 0 to 1

            let charSelectValue; // This value (0-1) determines character from "lightest" (0) to "densest" (1)
            if (invertBrightnessMap === 1) {
                // Light image areas map to "denser" characters (from end of characterSet)
                charSelectValue = normalizedBrightness;
            } else {
                // Dark image areas map to "denser" characters (default behavior)
                charSelectValue = 1.0 - normalizedBrightness;
            }

            // Select character from the characterSet (assumed to be ordered light to dense)
            // Use Math.round for better distribution across characters
            const charIndex = Math.max(0, Math.min(numChars - 1, Math.round(charSelectValue * (numChars - 1))));
            const charToDraw = chars[charIndex];

            // Calculate drawing position for the character (center of its cell)
            const drawX = c * charCellWidth + charCellWidth * 0.5;
            const drawY = r * charCellHeight + charCellHeight * 0.5;
            
            outCtx.fillText(charToDraw, drawX, drawY);
        }
    }

    return outputCanvas;
}

Free Image Tool Creator

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

Description

The Image To Japanese Character Art Converter transforms images into a unique form of artwork using Japanese characters. By sampling the brightness of different segments of an image and replacing those segments with characters based on their density, this tool creates a visually striking representation that combines the aesthetics of the original image with the intricacies of Japanese typography. This tool can be used for various creative purposes such as generating unique visuals for social media, producing custom art prints, or enhancing digital projects with culturally inspired designs.

Leave a Reply

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