【问题标题】:How do I save a canvas with filters applied, using these stackoverflow answers?如何使用这些 stackoverflow 答案保存应用了过滤器的画布?
【发布时间】:2017-10-10 03:02:57
【问题描述】:

我知道如何将 CSS 过滤器实际应用于图像的问题已被多次询问。给出的一些答案实际上并不使用 CSS 过滤器,但似乎仍然可以完成工作。不幸的是,我对 JavaScript 很陌生,我不明白这些答案。

所以,我的问题分为两部分:

  1. 由于其中一些答案已经过时,是否已开发出一种方法来保存应用了 CSS 过滤器的画布图像?

  2. 如果没有,我该如何实施这些 stackoverflow 答案之一中描述的解决方案?我本质上需要一个代码示例,将多个过滤器实际应用于图像或像素,这不包含在原始答案中。

谢谢

答案:

在第一个答案中,我迷失了循环中的“...”。在第二个答案中,没有关于第 4 步的详细信息。如果我是正确的,这两个都使用 CSS3 过滤器,这是我的首选Capture/save/export an image with CSS filter effects applied

我在这一步的第 3 步迷路了:is anyone solve about saving filtered canvas as an image?

再次,我对非 CSS 过滤器的应用感到迷茫:How to save image from canvas with css filters

JavaScript:

  // I know I eventually need to move these globals so they're passed as parameters.        
  var image; 
  var c; 
  var context; 
  var file; 

  // Begin File Open Code. 
  function fileOpen()
  {
    var fileInput = document.getElementById('fileInput');
    var fileDisplayArea = document.getElementById('iDisplay');

    fileInput.addEventListener('change', function(e)
    {
      file = fileInput.files[0];
      var imageType = /image.*/;
      if (file.type.match(imageType)) 
      {
        var reader = new FileReader();
        reader.onload = function(e)
        {                 
          iDisplay.innerHTML = "";
          image = new Image();

          image.src = reader.result;
          image.id = "I";               // Add an id attribute so the image editor code can access the image. // Image has since been moved to canvas.   
          iDisplay.appendChild(image);
          image.onload = function()
          {
            c = document.getElementById("C"); 
            context = c.getContext("2d");
            c.width = image.width; 
            c.height = image.height; 
            context.drawImage(image,0,0);  
          }                
        }
        reader.readAsDataURL(file); 
            }
      else
      {
        iDisplay.innerHTML = "File type not supported."
            }
        }); 
    setValues(); // Call setValues() as function exits to set Image Editing Code Hue Slider to 0.  
  }
  // End File Open Code 

  // Begin Image Editing Code. 
  var degrees = 0;
  var percentB = 100; 
  var percentC = 100;

  // Set initial values of sliders 
  function setValues()
  {      
    form1.brightness.value = 100;
    form1.contrast.value = 100;
    form1.hue.value = 0;      
  }

  // Get slider settings and apply changes to image
  function apply()
  { 
    degrees = form1.hue.value;
    percentC = form1.contrast.value;
    percentB = form1.brightness.value;
    // This is the crux of my question: How do I apply this properly, using the stackoverflow answers, so that the edited image may be saved?   
    if (document.getElementById("C") != null) document.getElementById("C").style.filter = "brightness(" + parseInt(percentB) + "%)" + " contrast(" + parseInt(percentC) + "%)" + " hue-rotate(" + parseInt(degrees) + "deg)";   
    if (document.getElementById("C") != null) document.getElementById("C").style.WebkitFilter = "brightness(" + parseInt(percentB) + "%)" + " contrast(" + parseInt(percentC) + "%)" + " hue-rotate(" + parseInt(degrees) + "deg)";   
  }
  // End Image Editing Code 

  // Canvas was not cooperating, it needed c.width not c.style.width, can probably remove these and replace with small default values.    
  function setCanvasWidth()
  {
    c.width = image.width;  
  }

  function setCanvasHeight()
  {
    c.height = image.height;  
  }

  // Begin File Save Code (or user can right click and save if filters get applied.  
  function save()
  {
    alert("Place file save code here.")
  }

HTML

 <!doctype html>
 <html lang="en">
 <head>
   <title>HTML5 CSS3 Javascript Image Editor</title>
   <meta charset="utf-8"/>
   <link rel="stylesheet" type="text/css" href="default.css"/>
   <script src="nav.js"></script>
   <script type="text/javascript">
   // JavaScript is in here. 
   </script>  

<!-- style elements specific to this page are placed in the style tags. -->  
<style>

  image  
  {
    max-width: 100%;
    display: block;
    margin: auto; 
    margin-left: auto; 
    margin-right: auto;  
  }

  #C 
  {
    max-width: 100%;
    display: block;
    margin: auto;     
    left: 0;
    right: 0;
    margin-left: auto; 
    margin-right: auto;  
  }

  #iDisplay 
  {
    margin-top: 2em;
    max-width: 100%;
    overflow-x: auto;
    margin-left: auto; 
    margin-right: auto;  
    display: none; 
  }

</style> 
</head>
  <body onload="setValues()">
<header>
  <a href="index.html"><img src="logoglow.png" alt="Logo Image" width="215" height="135" /></a>
  <a href="index.html"><img src="ac.png" alt="Header Image" width="800" height="135" /></a>
</header>
<main>
  <h3>An Ongoing Experiment in HTML5 / CSS3 / JavaScript Image Editing</h3>
  <div>
  <!-- Nav is floating left and Main is floating right, clear float styles (IF NEEDED) so they dont interfere with new image. -->     
    <p style="float:left;">  
    <input type="file" id="fileInput" onclick="fileOpen()"></p>
    <br style="clear:both">
  </div>
  <div id="iDisplay"></div>  
  <br style="clear:both"><br style="clear:both">
  <!-- <script>document.write('<img src="' + file + '"/>');</script><br><br> --> 
  <!-- <div style="overflow:scroll;">  -->
  <canvas style="color:#FFFFFF;" id="C" width="javascript:setCanvasWidth()" height="javascript:setCanvasHeight()">Your browser is too old to support this feature. <br>Please consider updating to a modern browser.</canvas>
  <!-- </div> --> 
  <!-- use javascript:function() to get width and height?  -->
  <div id="afterCanvas">  
  <br><br> 
  <form name="form1" id="form1id" action="javascript:save();" style="font-size:90%; text-align:center;">
    Brightness: <input type="range" name="brightness" min="0" max="200" step="5" onmousemove="apply()" ontouchmove="apply()" style="vertical-align:-7px;" />&nbsp; &nbsp;
    Contrast: <input type="range" name="contrast" min="0" max="200" step="5" onmousemove="apply()" ontouchmove="apply()" style="vertical-align:-7px;"/>&nbsp; &nbsp;
    Hue: <input type="range" name="hue" min="0" max="360" step="5" onmousemove="apply()" ontouchmove="apply()" style="vertical-align:-7px;"/>
    <br><br>  
    <input type="submit" style="float:left;" value="Save Changes" /> <!-- chnage to type="submit" if form action is needed --> 
  </form>
  </div>
</main>
</body>
</html>  

【问题讨论】:

  • 我可能应该提到,5 天后,我一切正常。除了我的问题。

标签: javascript html css canvas css-filters


【解决方案1】:

让我们从您的问题中来看看这部分,因为如果您只支持可以使用的浏览器,那么这就是您所需要的:

再一次,我对非 CSS 过滤器的应用感到迷茫:How to save image from canvas with css filters

上下文的filter property 就像 CSS 过滤器一样工作——它具有相同的功能——但重要的是要知道,与 CSS 不同的是,将过滤器应用于上下文并不会改变画布的当前图像。它仅适用于后续绘图操作。

这是一个例子。当您运行下面的代码 sn-p 时,您将看到两个画布。第一个应用了 CSS filter,第二个没有应用(这可以从第一个画布的边框是模糊的粉红色,而第二个是清晰的绿色这一事实证明)。

当您然后单击“复制图像”按钮时,代码

  1. 查看当前应用于第一个画布的 CSS 过滤器,
  2. 将此过滤器值应用于第二个上下文,
  3. 将第一个画布绘制到第二个画布上。

由于 2),3) 中的绘图操作将应用过滤器。

第二个画布现在看起来像第一个,但第二个画布现在真正包含了色调旋转和模糊的像素,而第一个仍然有红色和清晰的像素——你只是看不到因为 CSS过滤器。

此时,您可以将 second 画布保存为图像,它会看起来如预期的那样。

window.onload = function () {
  var cnv1 = document.getElementById("canvas1");
  var ctx1 = cnv1.getContext("2d");
  
  var cnv2 = document.getElementById("canvas2");
  var ctx2 = cnv2.getContext("2d");
  
  ctx1.font = "30px sans-serif";
  ctx1.fillStyle = "red";
  ctx1.fillText("Hello world!", 30, 80);

  var button = document.getElementById("button");
  button.onclick = function () {
  
    // take whatever CSS filter is applied to the first canvas
    var cssFilter = getComputedStyle(cnv1).filter;
    
    // use that filter as the second canvas' context's filter
    // all subsequent drawing operations will have this filter applied
    ctx2.filter = cssFilter;
    
    // take whatever is in canvas 1 and draw it onto canvas 2
    // the text on cnv1 is red and un-blurred (it's only the css
    // that makes it look otherwise), but the above filter will
    // cause blurring and hue-shifting to be applied to the drawImage
    // operation
    ctx2.drawImage(cnv1, 0, 0);
  };
}
* {
  vertical-align: top;
}

canvas {
  border: 2px solid green;
}
#canvas1 {
  filter: blur(2px) hue-rotate(180deg);
}
<canvas id="canvas1" width="200" height="200"></canvas>

<canvas id="canvas2" width="200" height="200"></canvas>

<button id="button">Copy image</button>

【讨论】:

  • 我已经服用了安眠药,目前无法实施和测试,但非常感谢您抽出宝贵时间。一个来自我镇静头脑的后续问题:我将如何将滑块(范围)值添加为#canvas1 中的变量?我确定我使用 JavaScript 执行此操作,但我不确定多个过滤器的语法。谢谢!
  • 您应该能够重复使用已有的代码。当用户更改值时,将值应用为 CSS style,就像您现在正在做的那样。只有在您想要保存图像的那一刻,您才创建第二个画布,并将您当前在第一个画布上拥有的任何 CSS 过滤器应用到其上下文。这就是我的示例中的var cssFilter = getComputedStyle(cnv1).filter; ctx2.filter = cssFilter; 所做的。然后复制图像 (ctx2.drawImage(cnv1, 0, 0);)。
  • Canvas ctx.filter 允许多个过滤器函数,就像 CSS filter 所做的那样(请注意,我的示例同时使用了 blurhue-rotate)。所以你不需要做任何特别的事情来支持它。
  • 我正在将它与我的代码合并,我已经可以看到它可以工作。我只需要清理一些东西,比如居中、移动控件等......所有常规的东西。 对此我非常感谢。这里有很多答案说纯 HTML5 / CSS3 / JavaScript 无法完成,但你的回答解决了这个问题。
  • 不客气。 FWIW,上下文 filter 属性是新的,所以这在很长一段时间内是不可能的(如果您需要支持旧浏览器,仍然不可能)。我可以想象(但还没有尝试过),也可以通过将 CSS 过滤器转换为 SVG 过滤器,然后将 SVG 绘制到新的画布上(SVG 过滤器比画布过滤器有更多的浏览器支持)。不过那会更混乱。无论如何,祝你好运:)
猜你喜欢
  • 1970-01-01
  • 2017-02-28
  • 2015-08-05
  • 2017-02-12
  • 1970-01-01
相关资源
最近更新 更多