元画像を変更せずに画像をグレースケールで表示する
公開:
更新:
タイトル通りなんですが、画像を1枚だけ用意して、それをカラーで使ったりグレースケールで使ったりしたいわけです。
IEには最初からフィルタが用意されていますが、クロスブラウザにできないかと思って調べてみました。
結果、何種類かあったので、デモを作ってみました。
元画像を変更せずに画像をグレースケールで表示する デモページ グレースケールにしたいセレクタにこれを指定すればおっけー。 Firefox 3.5以上にしか使えないっぽいですが、SVGでフィルタを作って、それをCSSで指定します。 Your SVG file will look like this: Save that as resources.svg, it can be reused from now on for any image you want to change to greyscale. FirefoxでHTML内で使えるSVGエフェクトについては以下のページを参照してください。 これの解説は色んなところにありますが、一番分かりやすかったページを参考にしました。 IE以外のモダンブラウザはHTML5の 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: 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). この方法のいいところは、IE以外のブラウザ(の最新版)なら、どれでも動くことです。 ただし、ピクセルごとに変換するということは、画像が大きかったり多かったりすると、とても遅くなるということです。IE用の指定
filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
SVGフィルタを使う
これは『Stack Overflow』にあった質問と回答からの引用です。<?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>
In your CSS you reference the filter using the Firefox specific filter property:.target {
filter: url(resources.svg#desaturate);
}
canvas
を使ってグレースケールにしてData URIに変換canvas
要素をサポートしているので、それを使ってピクセルごとにグレースケールに変換する、という方法です。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();
引用元ページではjQueryを使ってブラウザを判別し、IEならフィルタ、それ以外ならcanvasという感じで分岐させていました。
※分岐しないとIE 8でエラー出ます。
画像をいっぱい用意してやってみると分かりやすいと思います。
調べた結果、上記の3種類になったわけですが、クロスブラウザにするには1番目と3番目を組み合わせるしかないっぽいです。
重いという点に目をつぶれば、ですが。
よほどの事情がない限りは最初からグレースケールにした画像を用意する方がよさそうですね。残念。