如何使用 CSS 过滤器从画布中保存图像

IT技术 javascript html css canvas
2021-02-03 03:47:15

我需要在客户端使用 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;
    }

}

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

4个回答

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

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

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

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

如何计算各种过滤器可以在过滤器效果module级别 1 中找到另请参阅SVG 过滤器颜色矩阵

例子

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

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}
<canvas></canvas><img>

该属性现在是标准的一部分, Firefox 和 Chrome 都支持。
2021-04-12 03:47:15

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

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

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

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

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

另请注意html,问题处的图像似乎是 type jpg,而不是png

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

一个可能的“解决方法”可能是设置img src为 a data URIof image ;打电话

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

尽管如上所述,在上面的答案中,似乎不会保留css filterset at imgelement。


请注意,“解决方法”;“保存图像”在这里,将是“保存 html”;作为“下载”将是一个objectURL对的DOM html img元素。

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

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

尝试使用URL.createObjectURL, URL.revokeObjectURL; 设置css filterat img, 而不是canvaselement ;创建Blobimg outerHTMLtypetext/html; 创建参考URL.createObjectURLobjURL; 设置window.location.hrefobjURL电话URL.revokeObjectURL上的objectURL参考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>

谢谢你的详细回复。是带有过滤器的 .html 文件中的图像,但在计算机上保存时,此图像不包含过滤器(
2021-03-25 03:47:15
@ЕвгенийУсов 尝试将初始图像的 src 设置为数据 URI 而不是 url ?又见stackoverflow.com/questions/30066354/...stackoverflow.com/questions/29975138/...
2021-04-09 03:47:15