如何使用 CSS 过滤器从画布中保存图像
Posted
技术标签:
【中文标题】如何使用 CSS 过滤器从画布中保存图像【英文标题】:How to save image from canvas with CSS filters 【发布时间】:2015-08-05 04:46:37 【问题描述】:我需要在客户端使用 CSS 过滤器后保存图像(不使用使用后端)。到目前为止我所拥有的:
-
使用 CSS 过滤器
转换为画布
用
var data = myCanvas.toDataURL("image/png");
保存
哭了。图片已保存,没有效果。
索引.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;
但是,这会生成没有任何过滤器的图像。
【问题讨论】:
【参考方案1】:您的 CSS 属性实际上并未应用于画布数据。将 CSS 视为放置在画布元素上的另一层。您可以使用context.getImageData
来实现自己的图像过滤器,以获取原始RGBA 值数组,然后执行您的过滤器工作,然后使用context.putImageData
将其写回。但是,我认为您真的只想保存 CSS 过滤器的输出。您可以使用 rasterizeHTML 之类的工具完成此操作
【讨论】:
【参考方案2】:应用于画布的 CSS 过滤器不会应用于生成的图像。您要么需要在画布中复制过滤器,要么将相同的过滤器重新应用于生成的图像。
尝试将生成的图像数据放入 img 标签的源中并应用相同的过滤器。
【讨论】:
【参考方案3】:注意,如果img
的src
不在同源调用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"/>
一种可能的“解决方法”是将img
src
设置为图像的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
设置为objectURL
对DOM
img
元素outerHTML
的引用,这应该保留style
设置在.css("[vendorPrefix]-filter", filterVal)
的属性
尝试使用URL.createObjectURL
,URL.revokeObjectURL
;将 css
filter
设置为 img
,而不是 canvas
元素;创建 Blob
的 img
outerHTML
, type
: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>
【讨论】:
感谢您的详细回复。是的 .html 文件中带有过滤器的图像,但是当保存在计算机上时,此图像不包含过滤器( @ЕвгенийУсов 尝试将初始图像的 src 设置为数据 URI,而不是 url?另见***.com/questions/30066354/…、***.com/questions/29975138/…【参考方案4】:上下文对象上有一个鲜为人知的property,方便命名为filter
。
这可以将 CSS 过滤器作为参数并将其应用于位图。 但是,这不是官方标准的一部分,它仅适用于 Firefox,因此存在限制。。这是因为这个答案最初是写成official standard的一部分。
您可以检查此属性是否存在,如果存在则使用 CSS 过滤器,如果不存在,则使用后备手动将过滤器应用于图像。唯一的优势是可用时的真正性能。
CSS 和 DOM 与用于图像和画布的位图是一个独立的世界。位图本身不受 CSS 影响,只有充当位图镜子的元素。唯一的方法是在像素级别使用(当 context 的过滤器属性不可用时)。
如何计算各种过滤器可以在Filter Effects Module Level 1 中找到。另请参阅 SVG Filters 和 Color 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
<canvas></canvas><img>
【讨论】:
该属性现在是part of a standard,Firefox 和 Chrome 都支持。以上是关于如何使用 CSS 过滤器从画布中保存图像的主要内容,如果未能解决你的问题,请参考以下文章