【问题标题】:How to save image from canvas with CSS filters如何使用 CSS 过滤器从画布中保存图像
【发布时间】:2015-08-05 04:46:37
【问题描述】:

我需要在客户端使用 CSS 过滤器后保存图像(不使用使用后端)。到目前为止我所拥有的:

  1. 使用 CSS 过滤器
  2. 转换为画布
  3. var data = myCanvas.toDataURL("image/png");保存
  4. 哭了。图片已保存,没有效果。

索引.html

<div class="large-7 left">
    <img id="image1" src="./img/lusy-portret-ochki-makiyazh.jpg"/><br>
    <canvas id="myCanvas"></canvas>
</div>

Photo.js

var buttonSave = function() {
    var myCanvas = document.getElementById("myCanvas");
    var img = document.getElementById('image1');
    var ctx = myCanvas.getContext ? myCanvas.getContext('2d') : null; 
    ctx.drawImage(img, 0, 0, myCanvas.width, myCanvas.height);
        var grayValue = localStorage.getItem('grayValue');
        var blurValue = localStorage.getItem('blurValue');
        var brightnessValue = localStorage.getItem('brightnessValue');
        var saturateValue = localStorage.getItem('saturateValue');
        var contrastValue = localStorage.getItem('contrastValue');
        var sepiaValue = localStorage.getItem('sepiaValue');

        filterVal = "grayscale("+ grayValue +"%)" + " " + "blur("+ blurValue +"px)" + " " + "brightness("+brightnessValue+"%)" + " " + "saturate(" + saturateValue +"%)" + " " + "contrast(" + contrastValue + "%)" + " " + "sepia(" + sepiaValue + "%)" ;
        $('#myCanvas')
          .css('filter',filterVal)
          .css('webkitFilter',filterVal)
          .css('mozFilter',filterVal)
          .css('oFilter',filterVal)
          .css('msFilter',filterVal);

    var data = myCanvas.toDataURL("image/png");
    localStorage.setItem("elephant", data);
    if (!window.open(data)) {
        document.location.href = data;
    }

}

但是,这会生成没有任何过滤器的图像。

【问题讨论】:

    标签: javascript html css canvas


    【解决方案1】:

    您的 CSS 属性实际上并未应用于画布数据。将 CSS 视为放置在画布元素上的另一层。您可以使用context.getImageData 来实现自己的图像过滤器,以获取原始RGBA 值数组,然后执行您的过滤器工作,然后使用context.putImageData 将其写回。但是,我认为您真的只想保存 CSS 过滤器的输出。您可以使用 rasterizeHTML 之类的工具完成此操作

    【讨论】:

      【解决方案2】:

      应用于画布的 CSS 过滤器不会应用于生成的图像。您要么需要在画布中复制过滤器,要么将相同的过滤器重新应用于生成的图像。

      尝试将生成的图像数据放入 img 标签的源中并应用相同的过滤器。

      【讨论】:

        【解决方案3】:

        注意,如果imgsrc 不在同源调用var data = myCanvas.toDataURL("image/png"),可能会导致error

        Uncaught SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': tainted canvases may not be exported.
        

        另请注意,html 处的图片似乎是类型 jpg,而不是 png

        <img id="image1" src="./img/lusy-portret-ochki-makiyazh.jpg"/>
        

        一种可能的“解决方法”是将imgsrc 设置为图像的data URI;调用

        var data = myCanvas.toDataURL("image/jpg")
        

        尽管如前所述,在上面的答案中,似乎不会保留 css filter 设置在 img 元素。


        注意,“解决方法”;这里的“保存图片”是“保存 html”;因为“下载”将是 DOM html img 元素的 objectURL

        另请注意,img src 在已保存的html 文件中仍将是原始本地或外部图像的src;如果在加载前未转换为data URI

        方法是将window.location.href 设置为objectURLDOM img 元素outerHTML 的引用,这应该保留style 设置在.css("[vendorPrefix]-filter", filterVal) 的属性

        尝试使用URL.createObjectURLURL.revokeObjectURL;将 css filter 设置为 img ,而不是 canvas 元素;创建 Blobimg outerHTMLtype:text/html ;创建对URL.createObjectURL的引用:objURL;将 window.location.href 设置为 objURL ; 在objectURL 上调用URL.revokeObjectURL 参考objURL

        var buttonSave = function() {
          var img = document.getElementById("image1");
          // filters
          var grayValue = "0.2";
          var blurValue = "1px";
          var brightnessValue = "150%";
          var saturateValue = "0.2";
          var contrastValue = "0.2";
          var sepiaValue = "0.2";
          // `filterVal`
          var filterVal = "grayscale(" + grayValue + ") "
                          + "blur(" + blurValue + ") "
                          + "brightness(" + brightnessValue + ") "
                          + "saturate(" + saturateValue + ") "
                          + "contrast(" + contrastValue + ") "
                          + "sepia(" + sepiaValue + ")";
          // set `img` `filter` to `filterVal`
          $(img)
          .css({
            "webkit-filter": filterVal,
            "moz-filter": filterVal,
            "ms-filter": filterVal,
            "o-filter": filterVal
          });
          // create `blob` of `img` `outerHTML` ,
          // `type`:`text/html`
          var blob = new Blob([img.outerHTML], {
            "type": "text/html"
          });
          // create `objectURL` of `blob`
          var objURL = window.URL.createObjectURL(blob);
          console.log(objURL);
          // download `filtered` `img` as `html`
          var download = $("<a />", {
            "download": "image-" + $.now(),
            "href": objURL,
            // notify file is type `html` , not image
            "title":"click to download image as `html` file"
          }).appendTo("body");
          $(img).appendTo("a");
            
          $("a").on("click", function() {
            // set `location.href` to `objURL`
            window.location.href = objURL;
            $(window).one("focus", function() { 
              // revoke `objURL` when `window` regains `focus`
              // after "Save as" dialog
              window.URL.revokeObjectURL(objURL);
            });
          });
          
        }
        
        window.onload = buttonSave;
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
        </script>
        <div class="large-7 left">
          <img id="image1" src="http://lorempixel.com/200/200/cats" />
        </div>

        【讨论】:

        【解决方案4】:

        上下文对象上有一个鲜为人知的property,方便命名为filter

        这可以将 CSS 过滤器作为参数并将其应用于位图。 但是,这不是官方标准的一部分,它仅适用于 Firefox,因此存在限制。。这是因为这个答案最初是写成official standard的一部分。

        您可以检查此属性是否存在,如果存在则使用 CSS 过滤器,如果不存在,则使用后备手动将过滤器应用于图像。唯一的优势是可用时的真正性能。

        CSS 和 DOM 与用于图像和画布的位图是一个独立的世界。位图本身不受 CSS 影响,只有充当位图镜子的元素。唯一的方法是在像素级别使用(当 context 的过滤器属性不可用时)。

        如何计算各种过滤器可以在Filter Effects Module Level 1 中找到。另请参阅 SVG FiltersColor Matrix

        示例

        这将对其自身的上下文应用过滤器。如果过滤器属性不存在,则必须提供后备(此处未显示)。然后它将应用过滤器的图像提取为图像(右侧版本)。过滤器必须在下一次绘制操作之前设置。

        var img = new Image();
        img.crossOrigin = ""; 
        img.onload = draw; img.src = "//i.imgur.com/WblO1jx.jpg";
        
        function  draw() {
          var canvas = document.querySelector("canvas"),
              ctx = canvas.getContext("2d");
        
          canvas.width = this.width;
          canvas.height = this.height;
          
          // filter
          if (typeof ctx.filter !== "undefined") {
            ctx.filter = "sepia(0.8)";
            ctx.drawImage(this, 0, 0);
          }
          else {
            ctx.drawImage(this, 0, 0);
            // TODO: manually apply filter here.
          }
        
          document.querySelector("img").src = canvas.toDataURL();
        }
        canvas, img {width:300px;height:auto}
        &lt;canvas&gt;&lt;/canvas&gt;&lt;img&gt;

        【讨论】:

        猜你喜欢
        • 2013-03-18
        • 2017-02-28
        • 1970-01-01
        • 2017-02-12
        • 1970-01-01
        相关资源
        最近更新 更多