Please bookmark this page to avoid losing your image tool!

Image DNA Sequence Filter Effect Tool

(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.
async function processImage(originalImg, blockSizeParam = 10, fontFamily = 'monospace', characters = 'A,C,G,T', charColor = 'original', backgroundColor = '#FFFFFF') {
    const blockSize = Math.max(1, Math.floor(blockSizeParam)); // Ensure integer blockSize >= 1

    const imgWidth = originalImg.naturalWidth;
    const imgHeight = originalImg.naturalHeight;

    // Handle cases where the image might be empty or not loaded properly
    if (imgWidth === 0 || imgHeight === 0) {
        const emptyCanvas = document.createElement('canvas');
        emptyCanvas.width = 0;
        emptyCanvas.height = 0;
        // Optionally, log a warning or return a minimal canvas indicating an issue
        // console.warn("Input image has zero width or height.");
        return emptyCanvas;
    }

    // 1. Create a source canvas to draw the original image and get pixel data
    const srcCanvas = document.createElement('canvas');
    srcCanvas.width = imgWidth;
    srcCanvas.height = imgHeight;
    const srcCtx = srcCanvas.getContext('2d', { willReadFrequently: true }); // Hint for optimization

    try {
        srcCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
    } catch (e) {
        // This can happen if originalImg is not a valid drawable source (e.g. broken image)
        console.error("Error drawing image to source canvas:", e);
        const errorCanvas = document.createElement('canvas');
        errorCanvas.width = imgWidth; // Use original dimensions if available
        errorCanvas.height = imgHeight;
        const errorCtx = errorCanvas.getContext('2d');
        errorCtx.fillStyle = 'lightgray';
        errorCtx.fillRect(0, 0, errorCanvas.width, errorCanvas.height);
        errorCtx.fillStyle = 'red';
        errorCtx.font = '16px Arial';
        errorCtx.textAlign = 'center';
        errorCtx.textBaseline = 'middle';
        errorCtx.fillText('Error: Invalid image source.', errorCanvas.width / 2, errorCanvas.height / 2);
        return errorCanvas;
    }

    let imageData;
    try {
        imageData = srcCtx.getImageData(0, 0, imgWidth, imgHeight);
    } catch (e) {
        // This is a common issue with cross-origin images lacking CORS headers
        console.error("Error getting image data (this can be due to CORS policy):", e);
        const errorCanvas = document.createElement('canvas');
        errorCanvas.width = imgWidth;
        errorCanvas.height = imgHeight;
        const errorCtx = errorCanvas.getContext('2d');
        errorCtx.fillStyle = 'lightgray'; 
        errorCtx.fillRect(0, 0, errorCanvas.width, errorCanvas.height);
        errorCtx.fillStyle = 'red';
        errorCtx.font = '16px Arial';
        errorCtx.textAlign = 'center';
        errorCtx.textBaseline = 'middle';
        let errorMessage = 'Error: Could not process image pixels.';
        if (e.name === 'SecurityError') {
            errorMessage += ' (Cross-origin image?)';
        }
        errorCtx.fillText(errorMessage, errorCanvas.width / 2, errorCanvas.height / 2);
        return errorCanvas;
    }
    const srcPixels = imageData.data;

    // 2. Create the destination canvas
    const destCanvas = document.createElement('canvas');
    destCanvas.width = imgWidth;
    destCanvas.height = imgHeight;
    const destCtx = destCanvas.getContext('2d');

    // 3. Set background color for destination canvas
    destCtx.fillStyle = backgroundColor;
    destCtx.fillRect(0, 0, destCanvas.width, destCanvas.height);

    // 4. Parse characters parameter
    const charArray = characters.split(',').map(c => c.trim()).filter(c => c.length > 0);
    if (charArray.length === 0) {
        charArray.push('X'); // Use 'X' as a fallback if no valid characters are provided
    }

    // 5. Set font properties for drawing characters
    // Scale font size relative to block size, ensuring a minimum of 1px.
    const fontSize = Math.max(1, Math.floor(blockSize * 0.8)); 
    destCtx.font = `${fontSize}px ${fontFamily}`;
    destCtx.textAlign = 'center';
    destCtx.textBaseline = 'middle';

    // 6. Process image in blocks
    for (let yBlock = 0; yBlock < imgHeight; yBlock += blockSize) {
        for (let xBlock = 0; xBlock < imgWidth; xBlock += blockSize) {
            let rSum = 0, gSum = 0, bSum = 0;
            let numPixelsInBlock = 0;

            // Determine the actual width and height of the current block (may be smaller at image edges)
            const currentBlockWidth = Math.min(blockSize, imgWidth - xBlock);
            const currentBlockHeight = Math.min(blockSize, imgHeight - yBlock);

            // Iterate over pixels within the current block to calculate average color
            for (let y = yBlock; y < yBlock + currentBlockHeight; y++) {
                for (let x = xBlock; x < xBlock + currentBlockWidth; x++) {
                    const pixelStartIndex = (y * imgWidth + x) * 4; // Each pixel is 4 bytes (R,G,B,A)
                    rSum += srcPixels[pixelStartIndex];
                    gSum += srcPixels[pixelStartIndex + 1];
                    bSum += srcPixels[pixelStartIndex + 2];
                    // Alpha (srcPixels[pixelStartIndex + 3]) is available but ignored for average R,G,B
                    numPixelsInBlock++;
                }
            }

            if (numPixelsInBlock === 0) {
                continue; // Should not happen with blockSize >= 1 and valid img dimensions
            }

            const avgR = rSum / numPixelsInBlock;
            const avgG = gSum / numPixelsInBlock;
            const avgB = bSum / numPixelsInBlock;

            // Calculate brightness (simple average of R,G,B; range 0-255)
            const brightness = (avgR + avgG + avgB) / 3;

            // Select character based on brightness
            // Map brightness [0, 255] to an index in charArray [0, charArray.length - 1]
            const charIndex = Math.floor(brightness * charArray.length / 256);
            // Ensure index is within bounds (primarily for brightness === 255 edge case)
            const selectedChar = charArray[Math.min(charIndex, charArray.length - 1)];
            
            // Determine the color for the character
            let finalCharColor;
            if (charColor.toLowerCase() === 'original') {
                // Use the average color of the block for the character
                finalCharColor = `rgb(${Math.round(avgR)}, ${Math.round(avgG)}, ${Math.round(avgB)})`;
            } else {
                // Use the user-specified fixed color string
                finalCharColor = charColor;
            }
            destCtx.fillStyle = finalCharColor;

            // Calculate the center coordinates of the block for text placement
            const centerX = xBlock + currentBlockWidth / 2;
            const centerY = yBlock + currentBlockHeight / 2;
            
            destCtx.fillText(selectedChar, centerX, centerY);
        }
    }

    return destCanvas;
}

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 DNA Sequence Filter Effect Tool transforms images into a visual representation using DNA sequence characters, allowing you to create stylized versions of images. Users can adjust parameters such as block size, font, characters, character color, and background color to customize the output. This tool can be particularly useful for artists, educators, and scientists looking to create unique visual interpretations of images or to present biological data in a more engaging way.

Leave a Reply

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