【问题标题】:How to convert png base 64 to pixel array with out using image.src or image.onload?如何在不使用 image.onload 的 image.src 的情况下将 png base 64 转换为像素数组?
【发布时间】:2019-11-10 01:48:02
【问题描述】:

我想知道如何在 CSP 不允许的网站上加载 base64。这意味着我们不能做这样的事情:

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 是如何工作的,那么我们就可以做到。 有了这个: 任何帮助,将不胜感激 :) 谢谢!

【问题讨论】:

  • 数据url的base64部分是base64编码的文件内容。这个文件内容当然不是原始的像素数据,而是经过重新排列和压缩的像素数据,以便于读取、写入、存储和传输。您看到使用Image.src 的原因是因为它是让浏览器本地解码文件数据并将其转换为原始像素数据的唯一方法。如果您不想使用Image.src,您将不得不自己弄清楚如何解码图像。 W3C 上有一个PNG file format specification。祝你好运!
  • 另外,base64 规范之一是over here

标签: javascript image png pixel


【解决方案1】:

browserify代码here generated file (480kB):

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;

还有 sn-p 演示:

<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>

【讨论】:

  • 不完全是我想要的,我知道该怎么做。但在这种情况下,我不能使用 image.src。也许重读我的问题,然后再试一次。感谢您的回答:)
  • 不,它只是给了我与 browser.js 文件相同的东西。所以没关系。我只是不知道如何让 fs 工作。
  • 是的,我知道 CORS,不,我想将它作为 base64 保存在一个文件中。那是在网站中加载的。 CORS 不允许我将文件加载为 image.src。
  • 浏览器脚本位于生成文件的第 13859 - 13875 行。顺便说一句,您的图片数据不完整 - 应该有大约 903 个字节,但只有 800 个,所以 lib 报告了原始错误。 node.js 中的缓冲区和浏览器之间存在奇怪的区别 - 不适用于浏览器,并且 node.js 的缓冲区在 Browserify IIFE 之外是未知的。
  • 我认为只是这张图片,我可能没有复制整个字符串或其他东西。不过,它适用于其他图像。我永远无法弄清楚如何自己使用它。
【解决方案2】:

与您可能期望的不同,表示 PNG 图像的二进制数据不是像素数组。二进制数据有标题和描述文件的各种元数据,然后是压缩图像。

如果您需要在不使用本机浏览器解码功能的情况下从 png 二进制文件中获取像素,您要么必须自己研究 PNG 格式,要么使用可以让您访问图像像素的专用库。

有许多支持 PNG 格式的图像库。以下是一个可以为您解决问题的专业库。

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

你可以使用Browserify在前端使用这个库。

【讨论】:

  • 我应该如何准确地使用 pngjs 对其进行解码?方法是什么?
  • 好吧,当您遇到问题时,您将不得不参考文档、进行实验并发布更多问题。祝你好运。
  • 我想我会回到这个!
猜你喜欢
  • 2017-12-20
  • 1970-01-01
  • 2021-11-08
  • 2013-07-09
  • 2015-04-09
  • 2015-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多