アルファチャネルまたはSVGマスクを使用した画像のJPEG圧縮

こんにちは、Habr! 透過性を維持したpng-8での圧縮に関する最近の記事では、Webサイトでアルファチャネルを含む画像を使用できる一方で、ボリュームを大幅に削減できる非可逆圧縮アルゴリズムであるJPEGを使用できる手法を思い出しました。




背景

少し前、HTML5を知っている人が少なく、Flashが非常に一般的だったので、ActionScriptを学び、美しい「イメージ」サイトを作成する必要がありました。 通常、そのようなサイトは写真で非常に飽和しており、さらに、いくつかの効果のために、透明な背景の写真を使用する必要がありました(たとえば、影のある商品ユニットが異質な背景に対してどこかから美しく飛ぶ場合)。 しかしご存じのように、JPEGではアルファチャンネルをそれ自体に保存することはできません。PNGは可逆圧縮形式であるため、このような写真のサイズはやや大きいと言えます。 フラッシュでは、半透明の画像をJPEG圧縮で保存することができました。これは、アルファチャネルが画像とは別に保存され、その後JPEGで保存される2つの画像を受信することで実現しました。

後で、「通常の」htmlサイトの1つを作成し、大きな異質な半透明の背景も保存する必要がありましたが、png-32またはpng-8に保存しても満足のいく結果は得られませんでした。たくさん。 品質を落とすことなくアルファチャンネルで画像を保存できる技術を探して、SVGマスクに出会いました。



それは何のためですか?

架空の例を見てみましょう-内部に「穴」があるこのような写真が必要です:

PNG-32 (PNG-32、1870 Kバイト)



256色のPNG-8パレットに圧縮すると、画像が「殺され」ます。

PNG-8 (PNG-8、305 KB)



フラッシュを使用すると、適度なサイズのswfが得られますが、元の画像にはほとんど目が見えません。

フラッシュ (swf、453 kb)



原則として、swfを生成する便利さの複雑さではなく、すべてのデバイスでフラッシュを完全にサポートしていなければ、これを完了できたでしょう。 しかし、より便利なHTML5の代替手段があります!



メソッドの本質

メソッド自体は新しいものではなく、その説明は一部のリソースではめったに見つかりません。 しかし、残念ながら、それに関する情報は比較的少なく、少なくともハブに関する記事は見つかりませんでした

SVG標準では、 ビットマップイメージを埋め込むことができ、 マスクを適用することもできます。 では、フラッシュと同じようにすべてを実装しないのはなぜですか?

アルファチャネルを分離し、別のファイルに保存します。

画像 仮面 (JPEG、165/46 Kバイト)



合計ボリュームは.swf-211 Kbytes未満です!



SVGを作成します。
out.svg
<?xml version="1.0" encoding="utf-8" standalone="yes"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 240" width="300px" height="240px" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink"> <style> svg { -webkit-background-clip: text; } </style> <defs> <mask id="mymask"> <image xlink:href="mask.jpg" x="0" y="0" width="300px" height="240px" /> </mask> </defs> <image xlink:href="image.jpg" mask="url(#mymask)" x="0" y="0" width="300px" height="240px" /> </svg>
      
      





または、 data:URIを使用してファイルを直接svgに埋め込む(要求数を減らす)こともできますが、この場合、サイズは平均33%増加しますが、これはgzip圧縮で回避できます。



ブラウザ間の互換性はどうですか?

かつて、私はこの方法を「明るい未来」に任せました。その理由は、ブラウザーのSVGサポートがあまり良くなく、IE6要件の顧客がまだいましたが、時間がなくなり、この方法は「戦闘条件」で使用できるようになりました「。

HTMLでのSVGの実装については、Haberに関する記事が既に1つ2つありましたので、特にこの問題については触れません。 さらに、 -webkit-background-clip:text;を登録したことにお気づきかもしれません 、これは、古いサファリとクロムで実装されたオブジェクトを透明にするために必要です (最近のバージョンでは、このバグはすでに閉じられています)。

しかし、IE7、IE8はどうですか? この「死にゆく」オーディエンスのために、フラッシュを提供できます。フラッシュがない場合は、最悪の場合、重いPNG-32(またはある種のスタブ)をロードさせます。



解決策

SVGの接続方法から始めましょう。

SVGを実装するためのさまざまな方法を確認するために、特別なデモページを作成しました







オブジェクト/埋め込みを介した標準の接続方法(上記の記事へのリンク)に加えて、 <img>またはCSSを介してSVGに接続できます。 しかし、実際に示されているように、Firefoxとchromeの<img> SVGを通じて、データを介して埋め込まれたファイルでのみ表示されます:URI JavaScriptを使用してSVGを制御することはできません。 しかし、これらの事実を破棄する場合、この方法は「静的な」写真にさらに適しています。

SVGがサポートされていない場合(6〜8、Android <3.0など)、それをflashまたはpngに置き換えることができます。 既製のソリューションを探して、何も見つかりませんでしたので、自転車を作成しました(jQueryとSWFObjectを使用)。



HTMLには、jQuery、swfobject、およびスクリプト修正ライブラリが含まれています。 次に、任意の方法でsvgイメージを実装します。 ブラウザー間の互換性をサポートするために、埋め込みsvg要素のCSSクラスを選択し、data-altflashおよび/またはdata-altpng属性を介して代替ソースのURLを指定します。
index.html
 <!DOCTYPE html> <html> <head> <title>SVG alpha</title> <style> body { margin: 0; padding: 0; font: 12px/1 Arial, sans-serif; text-align: center; background: #ccc url(bg.png) repeat fixed left top; } h2 { margin-top: 2em; font-size: 120%; text-align: center; } table { width: 800px; margin: 0 auto; } table td { width: 300px; } object,iframe,embed,img,.svg-bg { width: 300px; height: 240px; margin: 0; padding: 0; border: 0px none; } object { -webkit-background-clip: text; } .svg-bg { background: transparent none no-repeat scroll left top; } </style> <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js" type="text/javascript"></script> <script type="text/javascript" src="svg.js"></script> <script type="text/javascript"> $(function(){ $('.svg').svg(); }); // init </script> </head> <body> <table> <tr> <th> object</th> <th> img (data:URI)</th> </tr> <tr> <td><object class="svg" data="out.svg" type="image/svg+xml" data-altflash="flash.swf" data-altpng="png-32.png"></object></td> <td><img class="svg" src="in.svg" alt="" data-altpng="png-32.png"/></td> </tr> </table> </body> </html>
      
      





svg.js(コードの品質をあまり批判しないでください。文字通りひざの上に書かれています):
svg.js
 $.supportSvg = function() { return document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image", "1.1"); }; $.svgReplaceImage = function() { var img = new Image(); img.src = $(this).data('altpng'); $(this).replaceWith(img); }; $.fn.svg = function() { if($.supportSvg()) return; this.filter('[data-altpng]:not([data-altflash])').each($.svgReplaceImage); var i = 0; this.filter('[data-altflash]').each(function() { var obj = this; this.id = 'svg-alt-'+(++i); swfobject.embedSWF($(this).data('altflash'), this.id, $(this).width(), $(this).height(), '10.0.0', 'expressInstall.swf', false, {wmode: 'transparent'}, false, function(e){ if(!e.success) $.svgReplaceImage.apply(obj); }); }); };
      
      





合計

したがって、画像のサイズを大幅に削減できます。 この方法は、ie7-ie9、firefox 13、chrome 19、opera 12、Safari 5(win)、android 2.3でテストされています。 他のブラウザでテストしてください。 ご清聴ありがとうございました!



参照資料

デモ

アーカイブミラー



PS。 マスクが任意の画像であるという誤解に遭遇するのはこれが初めてではありません。例として円形グラデーションを使用しました。実際には、マスクは任意の幾何学的な複雑さのJPEG画像です。



All Articles