简体   繁体   English

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

[英]How to save image from canvas with CSS filters

I need to save an image after using CSS filters on the client-side ( without using a backend).我需要在客户端使用 CSS 过滤器后保存图像(使用后端)。 What I have so far:到目前为止我所拥有的:

  1. Use CSS filters使用 CSS 过滤器
  2. Convert to canvas转换为画布
  3. Save with var data = myCanvas.toDataURL("image/png");使用var data = myCanvas.toDataURL("image/png");
  4. Crying.哭。 Image was saved without effects.图像保存没有效果。

Index.html索引.html

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

Photo.js照片.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;
    }

}

However, this produces an image without any filters.但是,这会生成没有任何过滤器的图像。

There is a little known property on the context object, conveniently named filter .上下文对象有一个鲜为人知的属性,方便地命名为filter

This can take a CSS filter as argument and apply it to the bitmap.这可以将 CSS 过滤器作为参数并将其应用于位图。 However, this is not part of the official standard and it only works in Firefox so there is the limitation.但是,这不是官方标准的一部分,它仅适用于 Firefox,因此存在限制。 . . This has since this answer was originally written become a part of the official standard .这已经因为这个答案最初被写入成为 官方标准的一部分。

You can check for the existence of this property and use CSS filters if it does, or use a fallback to manually apply the filters to the image if not.您可以检查此属性是否存在,如果存在则使用 CSS 过滤器,如果不存在,则使用回退手动将过滤器应用于图像。 The only advantage is really performance when available.唯一的优势是可用时的真正性能。

CSS and DOM is a separate world from the bitmaps that are used for images and canvas. CSS 和 DOM 与用于图像和画布的位图是一个独立的世界。 The bitmaps themselves are not affected by CSS, only the elements which acts as a looking-glass to the bitmap.位图本身不受 CSS 影响,只有充当位图镜子的元素。 The only way is to work with at pixel levels (when context 's filter property is not available).唯一的方法是在像素级别使用(当context的过滤器属性不可用时)。

How to calculate the various filters can be found in the Filter Effects Module Level 1 .如何计算各种过滤器可以在过滤器效果模块级别 1 中找到 Also see SVG Filters and Color Matrix .另请参阅SVG 过滤器颜色矩阵

Example例子

This will apply a filter on the context it self.这将对其自身的上下文应用过滤器。 If the filter property does not exist a fallback must be supplied (not shown here).如果过滤器属性不存在,则必须提供回退(此处未显示)。 It then extracts the image with applied filter as an image (version to the right).然后将应用过滤器的图像提取为图像(右侧的版本)。 The filter must be set before next draw operation.过滤器必须在下一次绘制操作之前设置。

 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>

CSS filters applied to the canvas will not be applied to the image that is produced.应用于画布的 CSS 过滤器不会应用于生成的图像。 You either need to replicate the filters in canvas or rather re apply the same filters to the generated image.您要么需要在画布中复制过滤器,要么将相同的过滤器重新应用于生成的图像。

Try putting the generated image data into the source of an img tag & apply the same filters.尝试将生成的图像数据放入 img 标签的源中并应用相同的过滤器。

Your CSS properties are not actually applied to the canvas data.您的 CSS 属性实际上并未应用于画布数据。 Think of the CSS as being another layer placed over the canvas element.将 CSS 视为放置在画布元素上的另一个层。 You can implement your own image filters by using context.getImageData to get an array of raw RGBA values, then do your filter work and then write it back with context.putImageData .您可以通过使用context.getImageData获取原始 RGBA 值数组来实现自己的图像过滤器,然后执行过滤器工作,然后使用context.putImageData将其写回。 However, I think you really just want to save the output of the CSS filters.但是,我认为您真的只想保存 CSS 过滤器的输出。 You may be able to do this using a tool like rasterizeHTML您可以使用rasterizeHTML 之类的工具执行此操作

Note, if src of img is not located at same origin calling var data = myCanvas.toDataURL("image/png") , may cause error注意,如果img src不在同一原点调用var data = myCanvas.toDataURL("image/png") ,可能会导致error

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

Note also that image at html at Question appear to be type jpg , not png另请注意,问题处html处的图像似乎是jpg类型,而不是png

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

A possible "workaround" could be to set img src as a data URI of image ;一种可能的“解决方法”是将img src设置为 image 的data URI calling打电话

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

Though as noted , at Answers above , would not appear to preserve css filter set at img element.尽管如上所述,在上面的回答中,似乎不会保留在img元素处设置的css filter


Note, "workaround" ;请注意,“解决方法”; "save image" here , would be "save html" ; “保存图像”在这里,将是“保存html”; as the "download" would be an objectURL of the DOM html img element.因为“下载”将是DOM html img元素的objectURL

Note also , img src within saved html file will still be original local or external src of image ;另请注意,保存的html文件中的img src仍将是图像的原始本地或外部src if not converted to data URI before loading.如果在加载前未转换为data URI

Approach is to set window.location.href as an objectURL reference to DOM img element outerHTML , which should preserve style attribute set at .css("[vendorPrefix]-filter", filterVal)方法是设置window.location.href作为objectURL参照DOM img元件outerHTML ,应保存style在属性集.css("[vendorPrefix]-filter", filterVal)

Try utilizing URL.createObjectURL , URL.revokeObjectURL ;尝试使用URL.createObjectURLURL.revokeObjectURL setting css filter at img , instead of canvas element ;img处设置css filter ,而不是canvas元素; creating Blob of img outerHTML , type : text/html ;创建img outerHTML Blobtypetext/html create reference to URL.createObjectURL : objURL ;创建对URL.createObjectURL引用: objURL set window.location.href to objURL ;window.location.href设置为objURL call URL.revokeObjectURL on objectURL reference objURL呼吁URL.revokeObjectURLobjectURL参考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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM