Unformed Building

元画像を変更せずに画像をグレースケールで表示する

公開:
更新:

パーマリンク

タイトル通りなんですが、画像を1枚だけ用意して、それをカラーで使ったりグレースケールで使ったりしたいわけです。
IEには最初からフィルタが用意されていますが、クロスブラウザにできないかと思って調べてみました。

結果、何種類かあったので、デモを作ってみました。

元画像を変更せずに画像をグレースケールで表示する デモページ

IE用の指定

filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);

グレースケールにしたいセレクタにこれを指定すればおっけー。

SVGフィルタを使う

Firefox 3.5以上にしか使えないっぽいですが、SVGでフィルタを作って、それをCSSで指定します。
これは『Stack Overflow』にあった質問と回答からの引用です。

Your SVG file will look like this:

<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1"
     baseProfile="full"
     xmlns="http://www.w3.org/2000/svg">
    <filter id="desaturate">
        <feColorMatrix type="matrix" values="0.3333 0.3333 0.3333 0 0
                                             0.3333 0.3333 0.3333 0 0
                                             0.3333 0.3333 0.3333 0 0
                                             0      0      0      1 0"/>
    </filter>
</svg>

Save that as resources.svg, it can be reused from now on for any image you want to change to greyscale.
In your CSS you reference the filter using the Firefox specific filter property:

.target {
    filter: url(resources.svg#desaturate);
}
Convert an image to grayscale in HTML/CSS - Stack Overflow

FirefoxでHTML内で使えるSVGエフェクトについては以下のページを参照してください。

Applying SVG effects to HTML content - MDC Doc Center

canvasを使ってグレースケールにしてData URIに変換

これの解説は色んなところにありますが、一番分かりやすかったページを参考にしました。

IE以外のモダンブラウザはHTML5のcanvas要素をサポートしているので、それを使ってピクセルごとにグレースケールに変換する、という方法です。

All modern browsers support the CANVAS tag which is allowed access to the image’s pixels. The code below will go through each pixel in the image and replace the color values with an average value. Here is the code:

var canvas = document.createElement('canvas');

var canvasContext = canvas.getContext('2d');

var imgW = imgObj.width;

var imgH = imgObj.height;
canvas.width = imgW;
canvas.height = imgH;
canvasContext.drawImage(imgObj, 0, 0);

var imgPixels = canvasContext.getImageData(0, 0, imgW, imgH);

for(var y = 0; y < imgPixels.height; y++){
     for(var x = 0; x < imgPixels.width; x++){
          var i = (y * 4) * imgPixels.width + x * 4;
          var avg = (imgPixels.data[i] + imgPixels.data[i + 1] + imgPixels.data[i + 2]) / 3;
          imgPixels.data[i] = avg;
          imgPixels.data[i + 1] = avg;
          imgPixels.data[i + 2] = avg;
     }
}
canvasContext.putImageData(imgPixels, 0, 0, 0, 0, imgPixels.width, imgPixels.height);

return canvas.toDataURL();

From the above code sample, you see that we created a canvas, loaded the image into it, and then changed the color values of each pixel in the image to an average value. After that we simply replaced the SRC of our image to the image changed in the canvas.

Using the same method you can also flip images using JavaScript. (We will create a tutorial for this in the future).

How to Convert Images to Grayscale using JavaScript ― ajaxBlender.com

この方法のいいところは、IE以外のブラウザ(の最新版)なら、どれでも動くことです。
引用元ページではjQueryを使ってブラウザを判別し、IEならフィルタ、それ以外ならcanvasという感じで分岐させていました。
※分岐しないとIE 8でエラー出ます。

ただし、ピクセルごとに変換するということは、画像が大きかったり多かったりすると、とても遅くなるということです。
画像をいっぱい用意してやってみると分かりやすいと思います。

調べた結果、上記の3種類になったわけですが、クロスブラウザにするには1番目と3番目を組み合わせるしかないっぽいです。
重いという点に目をつぶれば、ですが。

よほどの事情がない限りは最初からグレースケールにした画像を用意する方がよさそうですね。残念。