Как преобразовать PNG Base 64 в пиксельный массив без использования image.src или image.onload? - PullRequest
1 голос
/ 28 июня 2019

Мне было интересно, как загрузить base64 на сайты, на которых есть CSP, которые этого не позволяют. Это означает, что мы не можем делать такие вещи, как:

image.src = "data:image/png;base64..."

Так что я решил, что мне нужно найти другой подход. Я попытался преобразовать base64 в двоичную строку, а затем поработать с ней, чтобы получить UintArray, содержащий данные изображения пикселей.

Я не знаю, как получить и получить изображение из функции loadImage , и при этом я не знаю, что я делаю неправильно, когда получаю пиксель (-ы).

Я знаю, что преобразование двоичной строки в массив пикселей является неправильным, у base64 должен быть какой-то способ его преобразования, который неизвестен большинству из нас.

Вот мой код, который пытается решить эту проблему:

        var canvas = document.getElementById("canvas");

        var imageBase64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAB4CAYAAAC0CXGGAAAD2ElEQVR4Xu1cMWhTURRNXAJ1l8QhlWwBoRahOIlOpS4tNF1cig6CQ4SOGnAQomPADIKD0sWlKbRLSyfFSQJSC0K2YDPY4G6hi7p6z4d7uPxXCfFk+7nvv5/zzrnv3Xvf+ykWgp9er/f771sajUYx2IVpnre/8MPzPhDB5u1PACZeQkjxu/aRUcHd1py5ZoBS90cllPqBqfsTgImTEKMYp8HUAKL9ZyQkAGRlTj1A08/A4eGhG+rMz8/nCYUK0f5xnaEMRB8QRRPtXwBwhCdOQvgDW62Wif/L5bJp0u/3zXW1WnVVNBqNjH1hYcFcj8djc91ut91ogYYSAgB8iAEYkIyEmGSaO29djbduLLn29qd9195duRfyCQHIzFpiIKeEMFrEET45OXE1jPM4NsZ1BO2VSsXtPxxKCACMgBiAhImGEugTGP6y2AglyGIfDA5ZnUkAxACEz8kl1O12TT7w/s0PI+uLV7+Z659fr7jzOGt/+/4lc3+z2cyXDwgA8CEGWD6AAkYJoR19on7nl+sDg70Lxo6ax5uT+4AAiAGrgXAosbu762t8MHDt9XrdtS8vLxt78lhIAMQA8QGWE7Ny+MHBgavxxcVF186KxblzYgEQA/Z4D91ieri/ZjT7oPzEXKPm2Tw/gHUCfeL1+Lnp/9XSlrsuCIAYAKc+dwnhJD57dN18FfWB47nP7rqQ3AcEAGYhMRDNgZ99eWRuQR+YeTzravr0xbGxIwNPr71078ccObMOsCReAMSALTXSUILtiW1ubuZaB9bX113N455ZOB8QABhfjEbFAAoQc+JoGSUaC7H2rE5EnVgAiA+IAVYHQgnhmTjMyKKxEObEeKILfQB9tigAUIkTA3AsMywhDB3Y+Z/UVQnUOJ4EwNgo4wMCQOr/rDL3/zFwc3vVnIVY+37LDAKejcYRwhFlK2u0PZ4v2rr8wfyEogBAnUcMgEbDEsqUDndmzFfYIebE0ZUYMzL0ueOVUzdnzviAAAQrc2KAhdOTVlYJ5wMCkLg";

        canvas.width = 540;
        canvas.height = 360;

        var ctx = canvas.getContext('2d');

        function loadImage(base64)
        {
            var binary_string = window.atob(base64.split(",")[1]);
            var len = binary_string.length;
            var pixels = new Uint8Array(len);

            for (var i = 0; i < len; i++)        
            {
                pixels[i] = binary_string.charCodeAt(i);
            }

            putImageData(ctx, {
                data: pixels,
                width: 100,
                height: 100
            }, 0, 0);



            var img = new Image();
            img.crossOrigin = "Anonymous"; 

            console.log(pixels);

            return img;
        }

        loadImage(imageBase64);

        //ctx.drawImage(loadImage(imageBase64), 0, 0);



        function putImageData(ctx, imageData, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight) 
        {
            var data = imageData.data;
            var height = imageData.height;
            var width = imageData.width;

            dirtyX = dirtyX || 0;
            dirtyY = dirtyY || 0;
            dirtyWidth = dirtyWidth !== undefined ? dirtyWidth : width;
            dirtyHeight = dirtyHeight !== undefined ? dirtyHeight : height;

            var limitBottom = dirtyY + dirtyHeight;
            var limitRight = dirtyX + dirtyWidth;

            for (var y = dirtyY; y < limitBottom; y++) 
            {
                for (var x = dirtyX; x < limitRight; x++) 
                {
                    var pos = y * width + x;
                    ctx.fillStyle = 'rgba(' + data[pos * 4 + 0]
                                    + ',' + data[pos * 4 + 1]
                                    + ',' + data[pos * 4 + 2]
                                    + ',' + (data[pos * 4 + 3] / 255) + ')';
                    ctx.fillRect(x + dx, y + dy, 1, 1);
                }
            }
        }

Может быть, если мы сможем выяснить, как работает base64, мы сможем это сделать. И с этим: Любая помощь будет оценена :) Спасибо!

Ответы [ 2 ]

3 голосов
/ 28 июня 2019

В отличие от ожидаемого, двоичные данные, представляющие изображение PNG, не являются массивом пикселей.Двоичные данные имеют заголовки и различные метаданные, описывающие файл, а затем сжатое изображение.

Если вам нужно извлечь пиксели из двоичного файла png без использования встроенной функции декодирования браузера, вам нужно либо изучить PNGотформатируйте себя или используйте специализированную библиотеку, которая предоставит вам доступ к пикселям изображения.

Существует множество библиотек изображений, которые поддерживают формат PNG.Ниже приводится специализированная библиотека, которая может помочь вам.

https://www.npmjs.com/package/pngjs

Вы можете использовать Browserify , чтобы использовать эту библиотеку в клиентской части.

1 голос
/ 28 июня 2019

Код для просмотра здесь сгенерированный файл (480 КБ) :

var PNG = require('pngjs').PNG;

function getPNG(bin) {
    return PNG.sync.read(bin);
}

function loadImage(base64)
{
    var binary_string = Buffer.from(base64, 'base64');

    var png = getPNG(binary_string);

    return png;
}

window.getPNG = getPNG;
window.loadImage = loadImage;

И фрагмент кода:

<canvas id=canvas></canvas>
<script src="https://pastebin.com/raw/SN2vwZeg"></script>
<script>
var canvas = document.getElementById("canvas");

var imageBase64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAB4CAYAAAC0CXGGAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAMxSURBVHhe7doxaFNRGAXg6KRxlyRD4hpqqUEoTqJTaZcWTBeXoIPgEHcNCArR3TcIDpUsLq3QLi1Z1FECEitiVtshDe52jDbeM/Sd3ub3NtH7cvt/i6cgD6/5T9+9L+9MytHa2tovxD/K5bLzNQ4b9Xpn8efE0gX4Js4bz+ib+jaScbs2g2RIMzzu6+kI+RZeB6QZZePuAJOuryPkW/gdaLfbSHalUgnpZFyvrx1ImvA6wGq1WqwTmUwGyWi1WkhGPp9Hstvd3UUyZmdnkYxer4dk1Ov1of9GHSHfwuuANPPV9ddIdrVr80h29Y9bSHbR0h0kQ+qEjpBv4XWA90Jsb28PyY5nlnGnWDabRbLTvVDShNcBJp0PpL0Rk/Y+0v6f6Qj5Fn4HoiiKdeD9yg8k48Ll70jGz6+XkOykv3/z7kUko1qtagcS7fR1gHEnigt9JLvOZvz/jGeeaQeSLvwO8F5oY2MDya7T6SDZFYtFJLvFxUUkQ/dCSRdeB6QzsfQ8v9lsItnNzc0h2UnfN+iZOGnC78D9rWUk417mEZLBMy/9nuf7BHfiVe8ZkvFyfhXJ0A4kzenrACtsX0UyXDuwM/MJyU47kHThdUA6Az/9/ADJ4A6kHxaQ7Paf7yAZ3IHHV14g2fEZWUfIt/A6wPcB6TuxRqOBZLjeByqVCpIdf2em94GkCb8Drs+BXDsw6nMiHSHfJr8D0nMg7gC/E8dnYte9EJ+J+Z067gDTEfItvA7w3kd6/2fcz4UYv4vBeyMdId8mvwPX396KdWC5ewPJkN7/+dd7IX6/aDX3AcnQEfItvA6wwnoayeCZ5DOx616Iz8TcuZ2lfSQ7HSHfJr8D0nkgac+FmH4Crp/AqNfr9/vF6Wn8MJDuDF9AAsVWpL+FfPvvC+h2u8NL4Eg/Ad90Ab6JCxh36cZt5E+g0XBbYC6XO9jc0O2Wbk6DN6oRoFpFGIhvpv5OFCEc490KAhQXEI7xbRMB+B/MYgsYonH+JKs74LqAw6aGb55SRz5h+pl3T1PCBcVFSiPF4zPqAsbnyPdtMZEwhk/oJYz8l/hLGOdqww/bSimllFJKKaWUi1TqN5LWUoxlg3+MAAAAAElFTkSuQmCC"

var ctx = canvas.getContext('2d');

var png = loadImage(imageBase64.split(",")[1]);

putImageData(ctx, {
        data: png.data,
        width: png.width,
        height: png.height
    }, 0, 0);


function putImageData(ctx, imageData, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight) 
{
    var data = imageData.data;
    var height = imageData.height;
    var width = imageData.width;

    dirtyX = dirtyX || 0;
    dirtyY = dirtyY || 0;
    dirtyWidth = dirtyWidth !== undefined ? dirtyWidth : width;
    dirtyHeight = dirtyHeight !== undefined ? dirtyHeight : height;

    var limitBottom = dirtyY + dirtyHeight;
    var limitRight = dirtyX + dirtyWidth;

    for (var y = dirtyY; y < limitBottom; y++) 
    {
        for (var x = dirtyX; x < limitRight; x++) 
        {
            var pos = y * width + x;
            ctx.fillStyle = 'rgba(' + data[pos * 4 + 0]
                            + ',' + data[pos * 4 + 1]
                            + ',' + data[pos * 4 + 2]
                            + ',' + (data[pos * 4 + 3] / 255) + ')';
            ctx.fillRect(x + dx, y + dy, 1, 1);
        }
    }
}
</script>
...