ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScriptでスクリーンショット機能を実装

JavaScriptでスクリーンショット機能を実装

巴扎黑
巴扎黑オリジナル
2017-08-14 14:07:381938ブラウズ

JS を使用してスクリーンショットを撮るという考えは非常にばかげていると思います。第一に、JS にはオペレーティング システムのスクリーンショット機能を呼び出す権限がありません。第二に、ブラウザ (BOM) は関連するスクリーンショットを提供しません。いくつかの試行錯誤の後、私はいくつかのアイデアを思いつきました。これが、js スクリーンショット関数の実装コードを簡単に紹介したものです。最近、NetEase の Hearthstone の関連ページの開発に参加しました。私はカード グループ共有ページを作成中です (アドレス: ハースストーン ボックス カード グループ共有)。ユーザーはこのデッキを写真の形で友達と共有できます。元のアプローチは、サーバーを使用してページを画像に変換し、画像アドレスをフロントエンドに返すことでした。これは非常に優れており、サーバーは変換された画像をキャッシュすることもでき、次のリクエストでは画像アドレスを直接返すことができます。原理的には何も問題ありません。ただし、バックグラウンドで変換された画像がページのコンテンツと一致しないことがあり、一部のコンテンツが欠落していることがあり、PM の姉妹はこの問題を解決する必要があると非常に不満に思っています。とにかく、ページを画像に変換するインターフェースはバックグラウンドで実行されるので、それは私の仕事ではありません。密かに喜んでいたとき、バックグラウンドで同僚が、ページ内の一部のコンテンツが非同期で読み込まれるため (たとえば、下部の QR コードがキャンバスを通じて生成されるなど)、サーバーの変換が不安定になることがあると言いました。非同期的にレンダリングされたコンテンツは傍受できません。率直に言って、彼にはこの問題を解決する方法がありません。フロントエンドに非同期レンダリングを使用するように指示したのは誰でしょうか。最後に、リーダーは私に、JS を直接使用してスクリーンショットを撮ることができるかどうか試してほしいと言いました。そうすれば、サーバーへの負荷が軽減されるだけでなく、上記のバグも解決できます。

最初は、JS を使用してスクリーンショットを撮るというアイデアは非常にばかげていると思いました (私の無知のせいです。フロントエンドはここ数年で急速に発展しました): まず第一に、JS には次のアクセス許可がありません。オペレーティング システムのスクリーンショット機能、次にブラウザ (BOM) を呼び出しますが、関連するスクリーンショット インターフェイスは提供されません。どうすればいいですか?ご不明な点がございましたら、Google までお問い合わせください。次に、「JS html to png」を検索したところ、「render-html-to-an-image」を見つけました。回答の中で誰かが DOM をキャンバスに変換できると述べていました。またまたキャンバスです!興奮せずにはいられませんでした。山や川から抜け出す方法を見つけるのは本当に困難でしたが、別の村にはまだ明るい未来がありました。次に、dom to Canvas を検索し、有名な mdn ドキュメント Drawing_DOM_objects_into_a_canvas にたどり着きました。それから私はその文書を真剣に読み始めました。ドキュメントの冒頭で述べたように、DOM をキャンバスに変換することはできませんが、DOM を SVG に変換し、その SVG をキャンバスに描画することはできます。なぜ最初に dom を svg に変換する必要があるのか​​と疑問に思う人もいるかもしれません。これは、SVG が XML 表現を使用しており、その構造が DOM と一致しているためと考えられます。

以下は公式ドキュメントのステップバイステップのチュートリアルです:


1. Blob のメディアタイプは「image/svg+xml」である必要があります

2 svg 要素が必要ですimage/svg+xml"

2.需要一个 svg 元素

3.在 svg 元素里面插入一个 foreignObject 元素

4.在 foreignObject 元素里面放入符合规范的 html

把dom转成canvas就这么简单,就上面几个步骤。下面是文档给出的一上简单的demo:


<!doctype html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Document</title>
</head>
<body>
<canvas id="canvas" style="border:2px solid black;" width="200" height="200">
</canvas>
<script>
 var canvas = document.getElementById(&#39;canvas&#39;);
 var ctx = canvas.getContext(&#39;2d&#39;);
 var data = &#39;<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">&#39; +
  &#39;<foreignObject width="100%" height="100%">&#39; +
  &#39;<p xmlns="http://www.w3.org/1999/xhtml" style="font-size:40px">&#39; +
  &#39;<em>I</em> like &#39; +
  &#39;<span style="color:white; text-shadow:0 0 2px blue;">&#39; +
  &#39;cheese</span>&#39; +
  &#39;</p>&#39; +
  &#39;</foreignObject>&#39; +
  &#39;</svg>&#39;;
 var DOMURL = window.URL || window.webkitURL || window;
 var img = new Image();
 var svg = new Blob([data], {type: &#39;image/svg+xml&#39;});
 var url = DOMURL.createObjectURL(svg);
 img.onload = function() {
  ctx.drawImage(img, 0, 0);
  DOMURL.revokeObjectURL(url);
 }
 img.src = url;
</script>
</body>
</html>

复制代码,运行一下,哇,帅呆了,浏览器上出现了超酷的两行艺术字呢!

嗯,原来dom转成canvas这么简单啊?那我通过 document.body.innerHTML
3. svg で foreignObject 要素を要素に挿入します

4.仕様に準拠した HTML をForeignObject要素に配置します

dom を Canvas に変換するのは上記の手順と同じくらい簡単です。以下はドキュメントに記載されている簡単なデモです:

<!doctype html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Document</title>
 <style>
  .container {
   color: red;
  }
 </style>
</head>
<body>
<p class="container" >
 Hello World!
</p>
<canvas id="canvas" style="border:2px solid black;" width=200" height="200">
</canvas>
<script>
 var canvas = document.getElementById(&#39;canvas&#39;);
 var ctx = canvas.getContext(&#39;2d&#39;);
 var data = &#39;<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">&#39; +
  &#39;<foreignObject width="100%" height="100%">&#39; +
  &#39;<p xmlns="http://www.w3.org/1999/xhtml" style="font-size:40px">&#39; +
  document.querySelector(&#39;.container&#39;).innerHTML +
  &#39;</p>&#39; +
  &#39;</foreignObject>&#39; +
  &#39;</svg>&#39;;
 var DOMURL = window.URL || window.webkitURL || window;
 var img = new Image();
 var svg = new Blob([data], {type: &#39;image/svg+xml&#39;});
 var url = DOMURL.createObjectURL(svg);
 img.onload = function() {
  ctx.drawImage(img, 0, 0);
  DOMURL.revokeObjectURL(url);
 }
 img.src = url;
</script>
</body>
</html>

コードをコピーして実行します。すごいですね、2 行のクールなワードアートがブラウザに表示されます。

まあ、dom を Canvas に変換するのはとても簡単だということがわかりましたか?次に、 document.body.innerHTML を使用して body 内のすべての DOM を取り出し、foreignObject 要素に配置します。これでページ全体がキャプチャされます。 🎜🎜🎜デモは単なる Hello World ですが、実際のプロジェクトの Dom 構造はこれよりもはるかに複雑です。たとえば、外部スタイル シート、画像、一部のタグは XML 仕様に準拠していない可能性があります。終了タグなど)。以下は簡単な例です。 .container はインライン スタイルを使用しませんが、スタイル タグで定義されています。フォントは画像に変換された後は有効になりません。 🎜🎜🎜🎜
function convertHtml2Canvas() {
  html2canvas(document.body, {
   allowTaint: false,
   taintTest: true
  }).then(function(canvas) {
   document.body.appendChild(canvas);
  }).catch(function(e) {
   console.error(&#39;error&#39;, e);
  });
 }
🎜 外部スタイルは有効にならないため、JS を通じてすべての dom 要素をトラバースし、element.style オブジェクトを通じてすべてのスタイルをインライン スタイルに追加できます。このアイデアは良さそうですが、外部スタイルをインライン スタイルに変換する関数を実際には書くことができません。需要は逼迫しており、あれこれいじる時間はあまりないので、既成のライブラリを探したいと思います。そこで、もう一度Googleに行きました。幸いなことに、すぐに html2canvas というライブラリを見つけました。これは非常に強力でありながら、非常に簡単な方法でページ全体のスクリーンショットを撮ることができます。
function convertHtml2Canvas() {
  html2canvas(document.body, {
   allowTaint: false,
   taintTest: true
  }).then(function(canvas) {
   document.body.appendChild(canvas);
  }).catch(function(e) {
   console.error(&#39;error&#39;, e);
  });
 }

目前还有一个问题,就是这种方法默认是把整个页面截取下来的(就是说,会以你的innerHeight和innerWidth为边界,会存在大量的空白),可是,我的卡组只是占了页面的一小部分,我只想要卡组的部分啊。其实已经有了canvas就好办了,我们可以对它进行处理啊。大概思路是:1.把上面得到的canvas对象转成Blob并放到一个img元素。然后再把img.src绘制到canvas里面。这时候调用canvas.drawImage方法就可以截取我们想要的内容了。下面的两个函数分别是把canvas转成image以及反过来把image转成canvas。


// Converts canvas to an image
 function convertCanvasToImage(canvas) {
  var image = new Image();
  image.src = canvas.toDataURL("image/png", 0.1);
  return image;
 }
 // Converts image to canvas; returns new canvas element
 function convertImageToCanvas(image, startX, startY, width, height) {
  var canvas = document.createElement("canvas");
  canvas.width = width;
  canvas.height = height;
  canvas.getContext("2d").drawImage(image, startX, startY, width, height, 0, 0, width, height);
  return canvas;
 }

然后,再把我们上面的写的 convertHtml2Canvas 改成下面的:


function convertHtml2Canvas() {
  html2canvas(document.body, {
   allowTaint: false,
   taintTest: true
  }).then(function(canvas) {
   var img = convertCanvasToImage(canvas);
   document.body.appendChild(img);
   img.onload = function() {
    img.onload = null;
    canvas = convertImageToCanvas(img, 0, 0, 384, 696);
    img.src = convertCanvasToImage(canvas).src;
    $(img).css({
     display: &#39;block&#39;,
     position: &#39;absolute&#39;,
     top: 0,
     left: 400 + &#39;px&#39;
    });
   }
  }).catch(function(e) {
   console.error(&#39;error&#39;, e);
  });
 }

这时候就可以把它的页面的某部分内容进行截取下来了。效果如卡组分享测试页面。页面左边部分是DOM结构的,右边部分是则是使用html2canvas转换出来的图片。长得一模一样,毫无毛病哈。

关于JS页面截图的就写到这里啦,因为也只刚刚接触,很多东西也理解得不到位,欢迎各大神指点。后面会深入学习一下html2canvas的源码,进一步理解dom to canvas的原理。

以上がJavaScriptでスクリーンショット機能を実装の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。