画像の変化を比較(jpg品質)

Jpgの保存時の品質による差

品質の数字にマウスを合わせるとその画像に入れ替わります。全然変わらないじゃないかという方は、次の拡大で比べてください。

元の写真
元の写真
圧縮後の品質
下の数字で品質を選択
品質100908070605040302010 0

部分を拡大して比較

上の写真の真中あたりを拡大しています。90,80の高い画質でも輪郭にさざなみが立つようにノイズが加わるのが見えます。

元の写真
元の写真
圧縮後の品質
下の数字で品質を選択
品質100908070605040302010 0

制作意図

非可逆圧縮の例として教科書にも取り上げられるjpegですが、自分の写真の中から校庭のクロガネモチの花を使い、GIMPで品質を指定してそれぞれエクスポートして作りました。品質を表すパーセントの数値とファイルの大きさは比例しているわけではないので、実際にやってみなければ最良の点はわかりません。写真の内容にもよりますが90,80までで急激に圧縮されたあと、なだらかに圧縮されていきます。しかし、見た目の画質の変化は90,80までは余り変化がなく、その先で急激に悪くなるように感じられます。そこで圧縮率が大きく見た目の変化の少ない90〜80程度に最適な妥協点があることになります。

マウスを滑らせるだけで画質の変化が見て取れるようにしました。ファイルの大きさは数値で示しても直感的にはわからないので別のグラフで示しました。写真の下にファイルの大きさに対応したバーを表示して写真と同時に入れ替えても良かったかもしれません。

やってみると、意外に品質を落としてもわからない写真でした。変化のわかる写真を探すことも考えましたが平均的な写真であることも必要かと思い、そのままにしました。

ただし、90%でも確実に非可逆であることを示すために拡大図をつけました。様々な品質でjpgにしたものをGIMPの機能を使い、補完無しで拡大し同じ部分をトリミングしてpngで保存しました。ここでjpgだと余計なノイズが更にのってしまいます。

jpgの特徴がよく出たさざなみが立つようなノイズがよくわかります。jpgの原理を聞きかじったことがあればうなずける結果です。

もともとのページは非可逆圧縮で見ることができます。ベタな塗りつぶしや線画などはjpgに向かないことも実際に見比べることができます。

プログラムなど

javascript

プログラムはコンパクトです。 setevent()というfunctionをページ読み込み後に実行して品質の100,90,80,...の数字にイベントハンドラを取り付けています。onmouseoverイベントが起こったとはに呼び出されるのはforループ内で定義している名前のないfunctionです。

forはspanタグについて繰り返し、イベントハンドラを取り付けています。thisはonmouseoverした、それぞれのspan要素という意味になります。

変数codeの内容は、このspan要素の90,80,70といった文字列です。これを使って「品質90%」などと表示し、codeを含んだファイル名を指定して写真を入れ替えます。

codeの値が256になることはここではありません。実はもともと品質は100,90,80と10刻みではなく100,99,98,...でした。そして256色のインデクスカラーのpngも含めて比較できるページだったのです。256と書いてあったら256色の画像を表示していました。JPEGの圧縮率と画質の詳細比較で見ることができます。

もうひとつ、選択されている品質は背景色をつけています。当然マウスが外れたら元に戻す必要がありますが、onmouseoutは使わずに、一旦背景色をつけた要素をlasttarget変数に覚えておいて、transparentに指定することでもとに戻しています。

<script>
window.onload = function(){ 
 setevent("area11","area12","kurog"   ,".jpg","sel1");
 setevent("area21","area22","kuroge"  ,".png","sel2");
}
function setevent(area,txtarea,img,bext,selector){ 
    var ext = bext;
    var lasttarget = null;
    var target = document.getElementById(area);
    var txtnode = document.getElementById(txtarea).firstChild;
    var par = document.getElementById(selector);
    var spans = par.getElementsByTagName("span");
    for (var i=0;spans.length>i;i++){
        spans[i].onmouseover = function(){
            if (lasttarget) lasttarget.style.backgroundColor = "transparent";
            this.style.backgroundColor = "#00ffff";
            var code = this.firstChild.nodeValue;
            if (code!=256) {
                ext = bext;
                txtnode.nodeValue = "品質 " + code + "%";
            }else{
                ext = ".png";
                txtnode.nodeValue = code + "色";
            }
            target.src="images/"+img+code+ext;
            lasttarget = this;
        }
    }
}
</script>

html

写真が入れ替わる部分だけ示しています。<span>要素の間で改行してはいけません。半角スペースと改行の一つ以上の連続は一つの半角スペースにまとめられるので、1スペース空いてしまいます。改行するなら全部しないと100,90,80,...の隙間が等間隔になりません。現在の隙間はspan{margin:0 2px;} を使っています。

<table class="comp">
<tr>
<td><img src="images/kurog100.jpg" id="area11" alt="圧縮後の品質"></td>
</tr>
<tr><td id="area12">下の数字で品質を選択</td></tr>
<tr><td id="sel1" class="comp">品質<span>100</span><span>90</span><span>80</span><span>70</span><span>60</span><span>50</span><span>40</span><span>30</span><span>20</span><span>10</span> <span>0</span>
</td></tr>
</table>