2012年11月1日木曜日

svgを使って画像の右クリックによる保存を無効にする

※ie9対策を追加しました
まずはこの画像を右クリックしてローカルに保存してみて下さい.


出来ましたか?おそらく,保存のためのコンテキストメニューが存在しなかったと思います.となると,スクリプトを使ってメニューを書き換えているのでしょうか?いいえ,この画像には一切スクリプトを設定していません.さて,どうすればこのようなことが可能なのでしょう?

実はこの画像,通常のimg要素を使って表示しているわけではありません.HTML5のインラインsvgを使って表示しているのです.HTML5ではsvg(scalable vector graphics)要素を使ってベクタ画像を直接htmlコードに挿入することが可能となっており,ここではsvgの機能を使って画像を読み込んでいます.その為,一般的な画像に対するコンテキストメニューが表示されないのです.

いまいちピンとこないかと思いますので,具体的にどのようなコードを記述しているのか見てみましょう.
<svg style="display:none;">
 <defs>
  <image height="320" id="foochan" width="240" xlink:href="foochan.jpg"></image>
 </defs>
</svg>
<svg height="320px" style="display: block; margin: 0 auto;" title="ふーちゃん家出中(悲)" width="240px">
 <use xlink:href="#foochan"></use>
</svg>
img要素を使って直接画像を表示するよりもちょっと記述が長いですね.でも全て意味があります.
  • 二つ有るsvg要素がインラインsvgと呼ばれる画像要素で,HTML5ではこのsvg要素を使って画像を表示することができます.
  • defs要素は図形の雛形を定義するための要素です.
  • image要素はhtmlのimg要素に相当するもので,外部画像を読み込むためのものです.ここではdefs要素の配下で画像を読み込んでいるため,そのままでは外部に表示されることはありません.
  • use要素は図形のひな形をコピーする機能を持っています.ここでは上で読み込んだ画像をコピーし,画面に表示しています.
つまり,ここで見えている要素はuse要素なのです.use要素そのものは画像ではありませんから,右クリックしても画像を保存するためのメニューが表示されないのです.この動作はスクリプトと異なり静的に行われるため,javascriptが無効となっている環境においても同様の結果となります

※svgのimage要素はブラウザによって右クリックにより表示されるメニューに違いがあります.chromeでは画像の保存ができませんが,firefoxでは保存できてしまいます.従って,更にuse要素を使って画像を表示させる必要があります.

※ie9ではインラインsvgを右クリックした際にsvg画像をファイルに保存できてしまいます.svg画像に実際の画像へのurl文字列が含まれてしまうと意味がないため,隠しsvg要素でこっそり画像を読み込んでいます.

ソースコードを見たり,デバッグツールを使ってしまえばどの画像を読み込んでいるかはバレバレなのですが,画像を保存するにはそれなりにスキルが必要となるため,画像のカジュアルコピーを避けたい場合にある程度の効果を期待することができます.


この他にもuse要素を使った画像のコピーには使い途があります.例えば1画面内で一つの画像を複数の場所で使いまわすといった場合,html単体では同じsrc属性を設定したimg要素を複数用意する必要があります.すると,img要素の数だけhttpリクエストが発生する事になりますが(この部分憶測),同じ画像を読み込んでいるだけなので有る意味無駄です.

一方use要素を使った画像のコピーでは,画像を読み込んでいる場所が一箇所であるためこのような問題は発生しません.

※dataスキーマ形式で画像ファイルをhtmlファイルに埋め込んでいる場合にも有効な方法です.
※複数回読み込みの回避策にはcssのbackground-imageプロパティによる方法も考えられます.

補足)01/19 httpリクエストの云々の部分,実際にはこのようなことはありえないとの指摘があり,筆者もそうだと思います(だったら何のためのキャッシュ機構か?).内容を読み返してみたところ,むしろdataスキーマ形式で読み込んだ画像をhtml内部で使いまわす際にこそ有効じゃないかと考えています.画像埋め込みの箇所を1箇所に集約することで,ファイルサイズの肥大を抑えることが可能となります.

→このテクニックを使ってみた例
http://www.h2.dion.ne.jp/~defghi/spritesvg/imageCollector.htm
つーか,このスクリプトを作っていて気がついた.

0 件のコメント:

コメントを投稿