Javascript以dataURL格式生成透明的1X1像素

Posted

技术标签:

【中文标题】Javascript以dataURL格式生成透明的1X1像素【英文标题】:Javascript generate transparent 1X1 pixel in dataURL format 【发布时间】:2011-08-16 06:12:02 【问题描述】:

我想知道一种在 javascript 中生成单个像素并将其转换为 base64 的方法。理想的功能是:

function createPixel(hexColor, opacity)
   //...Calculate
   return base64DataURL;

我对图像处理不是很熟悉。任何格式都可以(png、gif 等)。我想用它来覆盖背景图像,(是的,我可以使用 rgba css3,但我试图将它与背景图像一起放置在一个元素上,所以我不会将一个元素覆盖在另一个元素之上以实现效果) .

提前致谢。

编辑:我不想使用画布,我相信你可以使用画布来获取 base64 数据URL,但我确信它不如字符串操作快。此外,我并不担心将图像转换为 base64,而是对创建图像更感兴趣。

【问题讨论】:

老实说,使用 canvas+toDataURL 可能是最简单的解决方案。否则,您基本上必须弄清楚给定颜色和不透明度的 1x1 图像如何以任何格式(例如 PNG)表示,然后在该信息上使用 JavaScript base64 编码器,或者找出模式和自己简化外部编码。真的值得吗? 您可能还会发现使用 <canvas> 实际上比 JavaScript base64 编码器更快。 谢谢,我想我会坚持使用画布。 【参考方案1】:

4 年多之后,这是一个更简单的解决方案,它生成标准 GIF,因此实际上可以在浏览器中工作(我无法让 PEM 解决方案在 任何东西中工作)并且最多数量级比 PEM/canvas 快。唯一的缺点是 GIF 不支持 alpha opacity - 但可以通过 CSS 控制。

它基于this JSFiddle(不知名的美女作者),但经过基本优化 - 重复使用 keyStr 并接受十六进制字符串('#FF0000')和十六进制文字(0xFF0000) - 后者更快(感谢icktoofay)。

<html>

<body onload="Test()">
  <script>
    function Test() 
      var img = new Image;
      img.src = createPixelGIF(0xff0000); // generate a red pixel data URI
      img.height = 100;
      img.width = 100; // optional: add dimensions
      document.body.appendChild(img); // add to the page
    

    // ROUTINES =============

    var createPixelGIF = (function() 

      var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

      return function createPixelGIF(hexColor) 
        return "data:image/gif;base64,R0lGODlhAQABAPAA" + encodeHex(hexColor) + "/yH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==";
      

      function encodeHex(hexColor) 
        var rgb;
        if (typeof hexColor == 'string') 
          var s = hexColor.substring(1, 7);
          if (s.length < 6) s = s[0] + s[0] + s[1] + s[1] + s[2] + s[2];
          rgb = [parseInt(s[0] + s[1], 16), parseInt(s[2] + s[3], 16), parseInt(s[4] + s[5], 16)];
         else
          rgb = [(hexColor & (0xFF << 16)) >> 16, (hexColor & (0xFF << 8)) >> 8, hexColor & 0xFF];

        return encodeRGB(rgb[0], rgb[1], rgb[2]);
      

      function encodeRGB(r, g, b) 
        return encode_triplet(0, r, g) + encode_triplet(b, 255, 255);
      

      function encode_triplet(e1, e2, e3) 
        enc1 = e1 >> 2;
        enc2 = ((e1 & 3) << 4) | (e2 >> 4);
        enc3 = ((e2 & 15) << 2) | (e3 >> 6);
        enc4 = e3 & 63;
        return keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4);
      

    )();
  </script>
</body>

</html>

更新的 JSPerf 结果:http://jsperf.com/base64image/4(上面的代码是“createPixelGIF2”)。你会看到我尝试了进一步的优化(3+4),但似乎 JS 更喜欢堆栈操作而不是难以阅读的组合函数:)

我还为 canvas 方法添加了一个更新的测试,由于某种原因,它排除了 canvas 对象的实例化 - 在实际使用中会看到的最大性能拖累。

【讨论】:

【参考方案2】:

这是一个完全跨浏览器兼容的实现,使用 &lt;canvas&gt; (demo @ jsfiddle)。

var canvas = document.createElement('canvas');

// http://code.google.com/p/explorercanvas/wiki/Instructions#Dynamically_created_elements
if (!canvas.getContext) G_vmlCanvasManager.initElement(canvas);

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

// for simplicity, assume the input is in rgba format
function createPixel(r, g, b, a) 
    ctx.fillStyle = 'rgba(' + [r,g,b,a].join() + ')';
    ctx.fillRect(0,0,1,1);
    // 'data:image/png;base64,'.length => 22
    return canvas.toDataURL('image/png','').substring(22);

我很想知道这与icktoofay's answer 的性能相比如何。请注意,对于 IE excanvas,这意味着性能几乎肯定会在那里更差(但有什么新功能)。

查看 jsperf:http://jsperf.com/base64image

【讨论】:

我进一步优化了我的答案,因此它不会每次都创建函数和查找表。看看优化后的版本如何与canvas 保持一致会很有趣。 而且,显然,某些浏览器中有一个原生 Base64 编码器 (window.btoa),所以我也添加了它。 好的,我更新了 jsperf。我确实正确调用了您的函数,对吗?您的优化版本(使用原生 btoa,如果存在)将另外 2 个从水中吹走。 是的,这是有道理的。将几个字符串连接在一起,然后进行 Base64 编码,这将比创建画布、渲染到其中、将其编码为 PNG,然后将其编码为 Base64 快得多。无论如何,我的 JavaScript 原生版本毫无用处。 PAM 是一种非常罕见的格式,不太可能被很多人使用。【参考方案3】:
function createPlaceholder(w, h) 
    var img = document.createElement('img');
    img.setAttribute('style', 'width:'+w+'px;height:'+h+'px;border:none;display:block');
    img.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==';
    return img;

(对于透明像素)

【讨论】:

【参考方案4】:

试试这个。它使用了一种有点深奥的图像格式(PAM),但你说任何格式都可以,而且它确实有效!它没有经过优化或其他任何东西,所以它可能很慢,但是嘿,它可以工作。

编辑:好的,我稍微优化了一下...

var createPixel=(function() 
    var table=[];
    for(var i=0;i<26;i++) 
        table.push(String.fromCharCode("A".charCodeAt(0)+i));
    
    for(var i=0;i<26;i++) 
        table.push(String.fromCharCode("a".charCodeAt(0)+i));
    
    for(var i=0;i<10;i++) 
        table.push(i.toString(10));
    
    table.push("+");
    table.push("/");
    function b64encode(x) 
        var bits=[];
        for(var i=0;i<x.length;i++) 
            var byte=x.charCodeAt(i);
            for(var j=7;j>=0;j--) 
                bits.push(byte&(1<<j));
            
        
        var output=[];
        for(var i=0;i<bits.length;i+=6) 
            var section=bits.slice(i, i+6).map(
                function(bit)  return bit?1:0; );
            var required=6-section.length;
            while(section.length<6) section.push(0);
            section=(section[0]<<5)|
                (section[1]<<4)|
                (section[2]<<3)|
                (section[3]<<2)|
                (section[4]<<1)|
                section[5];
            output.push(table[section]);
            if(required==2) 
                output.push('=');
            else if(required==4) 
                output.push('==');
            
        
        output=output.join("");
        return output;
    
    if(window.btoa) 
        b64encode=window.btoa;
    
    return function createPixel(hexColor, opacity) 
        var colorTuple=[
            (hexColor&(0xFF<<16))>>16,
            (hexColor&(0xFF<<8))>>8,
            hexColor&0xFF,
            Math.floor(opacity*255)
        ];
        var data="P7\nWIDTH 1\nHEIGHT 1\nDEPTH 4\nMAXVAL 255\nTUPLTYPE RGB_ALPHA\nENDHDR\n";
        colorTuple.forEach(function(tupleElement) 
            data+=String.fromCharCode(tupleElement);
        );
        var base64DataURL="data:image/pam;base64,"+b64encode(data);
        return base64DataURL;
    
)();

...但实际上,canvas 应该可以正常工作。

【讨论】:

好主意,但在 firefox4 或 IE8 中似乎没有为我显示输出... :/ "Failed to load url". @aaaidan:当然; PAM 相当少见。 Firefox 和 IE 不支持它是有道理的。 @aaaidan:您可以通过将 Base64 内容解码为 .pam 文件并使用 ImageMagick 进行转换来证明它有效。并不是说这对 OP 需要的东西有帮助。

以上是关于Javascript以dataURL格式生成透明的1X1像素的主要内容,如果未能解决你的问题,请参考以下文章

设置“dataURL”的值超出了配额

dataurl 到图像以在 php 中下载

JavaScript使用readAsDataURL读取图像文件

如何在 JavaScript 中将 Blob 转换为文件

Blob/DataURL/canvas/image的相互转换

js中图片base64格式转文件对象