フレクトのクラウドblog re:newal

http://blog.flect.co.jp/cloud/からさらに引っ越しています

video要素の再生中のシーンを印刷する

こんにちは、エンジニアの藤野です。

HTMLへの動画の埋め込みにvideo要素が使われるようになって久しいですが、これをブラウザの機能を用いて印刷するとどのようになるかご存知でしょうか?

とあるお客様から「動画の再生中のシーンを印刷したい」という要望を受け、調査したところ、各ブラウザによって結果が異なることが分かりました。

本記事では各ブラウザの動作と、「再生中のシーンを印刷する」方法を紹介します。

各ブラウザでの動作

下記環境で動作を確認しました。

macOS Mojave 上の

Windows 10 上の

  • Edge

確認に用いたコードは下記のとおりです。

<!DOCTYPE html>
<html>
<head>
</head>
<body>
<video controls id="v">
    <source src="v.mp4" type="video/mp4">
    Sorry, your browser doesn't support embedded videos.
</video>
</body>
</html>

v.mp4は、エッジデバイス上での画像認識で弊社岡田が投稿した「AndoroidでImage Classification」の動画ファイルです。

それでは各ブラウザでの動作を見ていきましょう。

Firefox

動画部分が真っ白になります。

ブラウザでの表示: Firefox ブラウザでの表示

印刷時の表示: Firefox 印刷時の表示

Chrome

動画部分が真っ白になります。

ブラウザでの表示: Chrome ブラウザでの表示

印刷時の表示: Chrome 印刷時の表示

ときどき表示できる場合もあったのですが、その条件は分かりませんでした。

Edge

実はEdgeでは再生中のシーンがそのまま印刷できます。 つまり、FirefoxChromeで同様の動作を実装すればよいことになります。

ブラウザでの表示: Edge ブラウザでの表示

印刷時の表示: Edge 印刷時の表示

実装の方針

  1. video要素をソースとしたcanvas要素を作成
  2. 画面と印刷時でvideo要素とcanvas要素の表示を切り替える

Canvasは要素の作成時にvideo要素をソースとすることができます。

https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage

これを用いることで、video要素の現在の再生中の画像をcanvasとして表示できます。 そして、画面と印刷時でvideo要素とcanvas要素の表示を切り替えることで、再生中のシーンを印刷します。

canvasへの表示

drawImageメソッドでcanvasを描画します。 また、beforeprint eventを使って、再生中のシーンが描画されるようにします。

window.addEventListener('beforeprint', drawCanvas);

function drawCanvas(){
    let video = document.getElementById("v");
    let canvas = document.getElementById("c");
    canvas.width = video.videoWidth;
    canvas.height = video.videoHeight;
    canvas.getContext("2d").drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
}

表示の切り替え

メディアクエリを使って画面(screen)と印刷(print)の表示を切り替えます。 CSS@mediaルールを使うとシンプルに実装できます。

@media screen {
    video { display: block; }
    canvas { display: none; }
}
@media print {
    video { display: none; }
    canvas { display: block; }
}

試してみる

Firefox

ブラウザでの表示: Firefox ブラウザでの表示2

印刷時の表示: Firefox 印刷時の表示2

印刷した瞬間のシーンが表示できました。

Chrome

ブラウザでの表示: Chrome ブラウザでの表示2

印刷時の表示: Chrome 印刷時の表示2

印刷した瞬間のシーンが表示できました。

終わりに

無事、印刷時にvideo要素の表示を再現することが出来ました。 ブラウザでwebページを印刷したときの表示は、配置の調整はあるものの大体そのままという先入観があったので、今回は勉強になりました。

最終的に作成したコードは下記のとおりです。

<!DOCTYPE html>
<html>
<head>
    <style>
        @media screen {
            video { display: block; }
            canvas { display: none; }
        }
        @media print {
            video { display: none; }
            canvas { display: block; }
        }
    </style>
    <script type="text/javascript">
        window.addEventListener('beforeprint', drawCanvas);

        function drawCanvas(){
            let video = document.getElementById("v");
            let canvas = document.getElementById("c");
            canvas.width = video.videoWidth;
            canvas.height = video.videoHeight;
            canvas.getContext("2d").drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
        }
    </script>
</head>
<body>
<video controls id="v">
    <source src="v.mp4" type="video/mp4">
</video>
<canvas id="c"></canvas>
</body>
</html>

本記事の作成にあたって、下記ページを参考にさせていただきました。

videoタグの動画をcanvasを使って表示する