捕获包含内联svg的div并将其下载为图像

时间:2017-06-13 07:39:30

标签: jquery angularjs reactjs ember.js aurelia

我编写代码来使用html5捕获页面的屏幕截图。一切都很好,除非页面包含svg。当我将svg转换为内联svg后,截图未捕获内联svg。

请检查https://jsfiddle.net/7bqukhff/4/

<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.3/FileSaver.min.js"></script>
<script src="https://github.com/niklasvh/html2canvas/releases/download/0.5.0-alpha1/html2canvas.svg.js"></script>
<script src="https://github.com/niklasvh/html2canvas/releases/download/0.5.0-alpha1/html2canvas.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div id="wrapper">
   <h1>Scrrenshot</h1>
   <div class="img-div"><img src='https://istack.000webhostapp.com/1tf.svg'></div>
   <form class="cf">
      <div class="half left cf">
         <input type="text" id="input-name" placeholder="Name">
         <input type="email" id="input-email" placeholder="Email address">
         <input type="text" id="input-subject" placeholder="Subject">
      </div>
      <div class="half right cf">
         <textarea name="message" type="text" id="input-message" placeholder="Message"></textarea>
      </div>
      <input type="submit" value="Submit" id="input-submit">
   </form>
</div>
<a class="btn btn-success" href="javascript:void(0);" onclick="generate();">Generate Screenshot »</a>

$(function() {

   $('img').each(function() {

      var $img = jQuery(this);
      var imgID = $img.attr('id');
      var imgClass = $img.attr('class');
      var imgURL = $img.attr('src');

      jQuery.get(imgURL, function(data) {
         // Get the SVG tag, ignore the rest
         var $svg = jQuery(data).find('svg');

         // Add replaced image's ID to the new SVG
         if (typeof imgID !== 'undefined') {
            $svg = $svg.attr('id', imgID);
         }
         // Add replaced image's classes to the new SVG
         if (typeof imgClass !== 'undefined') {
            $svg = $svg.attr('class', imgClass + ' replaced-svg');
         }
         // Remove any invalid XML tags as per http://validator.w3.org
         $svg = $svg.removeAttr('xmlns:a');

         // Replace image with new SVG
         $img.replaceWith($svg);

      }, 'xml');

   });
});

(function(exports) {
   function urlsToAbsolute(nodeList) {
      if (!nodeList.length) {
         return [];
      }
      var attrName = 'href';
      if (nodeList[0].__proto__ === HTMLImageElement.prototype || nodeList[0].__proto__ === HTMLScriptElement.prototype) {
         attrName = 'src';
      }
      nodeList = [].map.call(nodeList, function(el, i) {
         var attr = el.getAttribute(attrName);
         if (!attr) {
            return;
         }
         var absURL = /^(https?|data):/i.test(attr);
         if (absURL) {
            return el;
         } else {
            return el;
         }
      });
      return nodeList;
   }

   function screenshotPage() {
      var wrapper = document.getElementById('wrapper');
      html2canvas(wrapper, {
         onrendered: function(canvas) {
            canvas.toBlob(function(blob) {
               saveAs(blob, 'myScreenshot.png');
            });
         }
      });
   }

   function addOnPageLoad_() {
      window.addEventListener('DOMContentLoaded', function(e) {
         var scrollX = document.documentElement.dataset.scrollX || 0;
         var scrollY = document.documentElement.dataset.scrollY || 0;
         window.scrollTo(scrollX, scrollY);
      });
   }

   function generate() {
      screenshotPage();
   }
   exports.screenshotPage = screenshotPage;
   exports.generate = generate;
})(window);

对于这个特定的svg没有问题,但对于某些svg,捕获的图像与原始图像不同。

是否有任何方法可以在不使用html画布的情况下捕获屏幕截图?如果不能如何更改我的代码以正确捕获svg元素?

我想现在每个人都熟悉精彩的屏幕截图扩展https://www.awesomescreenshot.com/。他们如何进行这种截屏?

Angular 1(不是2或以上),React JS,Vue.js,Aurelia js或任何现代JavaScript库中是否有任何方法可以截取屏幕截图?

1 个答案:

答案 0 :(得分:1)

您可以使用名为canvg的JavaScript库(用于在画布上正确呈现SVG)以及html2canvas来实现此目的。

ᴡᴏʀᴋɪɴɢᴡᴏʀᴋɪɴɢxᴀᴍᴘʟᴇ

$(function() {

   $('img').each(function() {

      var $img = jQuery(this);
      var imgID = $img.attr('id');
      var imgClass = $img.attr('class');
      var imgURL = $img.attr('src');

      jQuery.get(imgURL, function(data) {
         // Get the SVG tag, ignore the rest
         var $svg = jQuery(data).find('svg');

         // Add replaced image's ID to the new SVG
         if (typeof imgID !== 'undefined') {
            $svg = $svg.attr('id', imgID);
         }
         // Add replaced image's classes to the new SVG
         if (typeof imgClass !== 'undefined') {
            $svg = $svg.attr('class', imgClass + ' replaced-svg');
         }
         // Remove any invalid XML tags as per http://validator.w3.org
         $svg = $svg.removeAttr('xmlns:a');

         // Replace image with new SVG
         $img.replaceWith($svg);

      }, 'xml');

   });
});

(function(exports) {
   function urlsToAbsolute(nodeList) {
      if (!nodeList.length) {
         return [];
      }
      var attrName = 'href';
      if (nodeList[0].__proto__ === HTMLImageElement.prototype || nodeList[0].__proto__ === HTMLScriptElement.prototype) {
         attrName = 'src';
      }
      nodeList = [].map.call(nodeList, function(el, i) {
         var attr = el.getAttribute(attrName);
         if (!attr) {
            return;
         }
         var absURL = /^(https?|data):/i.test(attr);
         if (absURL) {
            return el;
         } else {
            return el;
         }
      });
      return nodeList;
   }

   function screenshotPage() {
      var wrapper = document.getElementById('wrapper');
      html2canvas(wrapper, {
         onrendered: function(canvas) {
            function getOffset(el) {
               el = el.getBoundingClientRect();
               return {
                  left: el.left + window.scrollX,
                  top: el.top + window.scrollY
               }
            }
            var cachedCanvas = canvas;
            var ctx = canvas.getContext('2d');
            var svgs = document.querySelectorAll('svg');
            svgs.forEach(function(svg) {
               var svgWidth = svg.width.baseVal.value;
               var svgHeight = svg.height.baseVal.value;
               var svgLeft = getOffset(svg).left - 40;
               var svgTop = getOffset(svg).top - 62;
               var offScreenCanvas = document.createElement('canvas');
               offScreenCanvas.width = svgWidth;
               offScreenCanvas.height = svgHeight;
               canvg(offScreenCanvas, svg.outerHTML);
               ctx.drawImage(cachedCanvas, 0, 0);
               ctx.drawImage(offScreenCanvas, svgLeft, svgTop);
            });
            canvas.toBlob(function(blob) {
               saveAs(blob, 'myScreenshot.png');
            });
         }
      });
   }

   function addOnPageLoad_() {
      window.addEventListener('DOMContentLoaded', function(e) {
         var scrollX = document.documentElement.dataset.scrollX || 0;
         var scrollY = document.documentElement.dataset.scrollY || 0;
         window.scrollTo(scrollX, scrollY);
      });
   }

   function generate() {
      screenshotPage();
   }
   exports.screenshotPage = screenshotPage;
   exports.generate = generate;
})(window);
@import url(https://fonts.googleapis.com/css?family=Merriweather);
$red: #e74c3c;
*,
*:before,
*:after {
   @include box-sizing(border-box);
}

html,
body {
   background: #f1f1f1;
   font-family: 'Merriweather', sans-serif;
   padding: 1em;
}

h1 {
   text-align: center;
   color: #a8a8a8;
   @include text-shadow(1px 1px 0 rgba(white, 1));
}

form {
   border: 2px solid blue;
   margin: 20px auto;
   max-width: 600px;
   padding: 5px;
   text-align: center;
}

input,
textarea {
   border: 0;
   outline: 0;
   padding: 1em;
   @include border-radius(8px);
   display: block;
   width: 100%;
   margin-top: 1em;
   font-family: 'Merriweather', sans-serif;
   @include box-shadow(0 1px 1px rgba(black, 0.1));
   resize: none;
   &:focus {
      @include box-shadow(0 0px 2px rgba($red, 1)!important);
   }
}

#input-submit {
   color: white;
   background: $red;
   cursor: pointer;
   &:hover {
      @include box-shadow(0 1px 1px 1px rgba(#aaa, 0.6));
   }
}

textarea {
   height: 126px;
}


}
.half {
   float: left;
   width: 48%;
   margin-bottom: 1em;
}
.right {
   width: 50%;
}
.left {
   margin-right: 2%;
}
@media (max-width: 480px) {
   .half {
      width: 100%;
      float: none;
      margin-bottom: 0;
   }
}

/* Clearfix */
.cf:before,
.cf:after {
   content: " ";
   /* 1 */
   
   display: table;
   /* 2 */
}
.cf:after {
   clear: both;
}
.half.left.cf > input {
   margin: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.3/FileSaver.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/canvg@2.0.0-beta.1/dist/browser/canvg.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wrapper">
   <h1>Scrrenshot</h1>
   <div class="img-div">
      <img src='https://istack.000webhostapp.com/1tf.svg'>
   </div>
   <form class="cf">
      <div class="half left cf">
         <input type="text" id="input-name" placeholder="Name">
         <input type="email" id="input-email" placeholder="Email address">
         <input type="text" id="input-subject" placeholder="Subject">
      </div>
      <div class="half right cf">
         <textarea name="message" type="text" id="input-message" placeholder="Message"></textarea>
      </div>
      <input type="submit" value="Submit" id="input-submit">
   </form>
</div>
<a class="btn btn-success" href="javascript:void(0);" onclick="generate();">Generate Screenshot »</a>