[解決済み】HTML5キャンバスの画像サイズを変更する
質問
クライアント側でjavascriptとcanvas要素を使ってサムネイル画像を作成しようとしているのですが、画像を縮小するとひどい状態になります。 まるでフォトショップで再サンプリングを「Bicubic」ではなく「Nearest Neighbor」に設定して縮小したかのような感じです。 これを正しく表示させることが可能なのは分かっています。 このサイト は、キャンバスを使ってもうまくできます。 私は、"[Source]" リンクに示されているように、彼らが行うのと同じコードを使用してみましたが、それはまだひどいように見えます。 私が見逃している何か、設定しなければならない何か、があるのでしょうか?
EDIT
jpgのサイズを変更しようとしています。 リンク先のサイトとフォトショップで同じjpgのリサイズを試しましたが、縮小しても問題なく表示されます。
以下は該当するコードです。
reader.onloadend = function(e)
{
var img = new Image();
var ctx = canvas.getContext("2d");
var canvasCopy = document.createElement("canvas");
var copyContext = canvasCopy.getContext("2d");
img.onload = function()
{
var ratio = 1;
if(img.width > maxWidth)
ratio = maxWidth / img.width;
else if(img.height > maxHeight)
ratio = maxHeight / img.height;
canvasCopy.width = img.width;
canvasCopy.height = img.height;
copyContext.drawImage(img, 0, 0);
canvas.width = img.width * ratio;
canvas.height = img.height * ratio;
ctx.drawImage(canvasCopy, 0, 0, canvasCopy.width, canvasCopy.height, 0, 0, canvas.width, canvas.height);
};
img.src = reader.result;
}
EDIT2です。
どうやら私の勘違いのようで、リンク先のサイトでは画像の縮小がうまくいっていなかったようです。 他の方法も試してみましたが、どれも良くは見えませんでした。 これは、異なる方法の結果です。
フォトショップ
キャンバスです。
画像レンダリング:optimizeQualityが設定され、幅/高さでスケーリングされた画像。
image-rendering: optimizeQuality が設定され、-moz-transform で拡大縮小された画像です。
pixasticでキャンバスリサイズを行う。
これは、firefoxがバイキュービックサンプリングを想定して使っていないことを意味しているのでしょう。 実際に追加されるまで待つしかないですね。
EDIT3:
解決方法は?
では、すべてのブラウザ(実際、Chrome 5はかなり良いものを提供してくれました)が十分なリサンプリング品質を与えてくれない場合、どうすればいいのでしょうか?それなら、自分で実装すればいいのです。Web 3.0、HTML5対応ブラウザ、超最適化JIT JavaScriptコンパイラ、マルチコア(†)マシン、大容量メモリ、何を恐れているんだ?javascriptにはjavaという単語があるんだから、性能は保証されているはずでしょう?見よ、このサムネイル生成コードを。
// returns a function that calculates lanczos weight
function lanczosCreate(lobes) {
return function(x) {
if (x > lobes)
return 0;
x *= Math.PI;
if (Math.abs(x) < 1e-16)
return 1;
var xx = x / lobes;
return Math.sin(x) * Math.sin(xx) / x / xx;
};
}
// elem: canvas element, img: image element, sx: scaled width, lobes: kernel radius
function thumbnailer(elem, img, sx, lobes) {
this.canvas = elem;
elem.width = img.width;
elem.height = img.height;
elem.style.display = "none";
this.ctx = elem.getContext("2d");
this.ctx.drawImage(img, 0, 0);
this.img = img;
this.src = this.ctx.getImageData(0, 0, img.width, img.height);
this.dest = {
width : sx,
height : Math.round(img.height * sx / img.width),
};
this.dest.data = new Array(this.dest.width * this.dest.height * 3);
this.lanczos = lanczosCreate(lobes);
this.ratio = img.width / sx;
this.rcp_ratio = 2 / this.ratio;
this.range2 = Math.ceil(this.ratio * lobes / 2);
this.cacheLanc = {};
this.center = {};
this.icenter = {};
setTimeout(this.process1, 0, this, 0);
}
thumbnailer.prototype.process1 = function(self, u) {
self.center.x = (u + 0.5) * self.ratio;
self.icenter.x = Math.floor(self.center.x);
for (var v = 0; v < self.dest.height; v++) {
self.center.y = (v + 0.5) * self.ratio;
self.icenter.y = Math.floor(self.center.y);
var a, r, g, b;
a = r = g = b = 0;
for (var i = self.icenter.x - self.range2; i <= self.icenter.x + self.range2; i++) {
if (i < 0 || i >= self.src.width)
continue;
var f_x = Math.floor(1000 * Math.abs(i - self.center.x));
if (!self.cacheLanc[f_x])
self.cacheLanc[f_x] = {};
for (var j = self.icenter.y - self.range2; j <= self.icenter.y + self.range2; j++) {
if (j < 0 || j >= self.src.height)
continue;
var f_y = Math.floor(1000 * Math.abs(j - self.center.y));
if (self.cacheLanc[f_x][f_y] == undefined)
self.cacheLanc[f_x][f_y] = self.lanczos(Math.sqrt(Math.pow(f_x * self.rcp_ratio, 2)
+ Math.pow(f_y * self.rcp_ratio, 2)) / 1000);
weight = self.cacheLanc[f_x][f_y];
if (weight > 0) {
var idx = (j * self.src.width + i) * 4;
a += weight;
r += weight * self.src.data[idx];
g += weight * self.src.data[idx + 1];
b += weight * self.src.data[idx + 2];
}
}
}
var idx = (v * self.dest.width + u) * 3;
self.dest.data[idx] = r / a;
self.dest.data[idx + 1] = g / a;
self.dest.data[idx + 2] = b / a;
}
if (++u < self.dest.width)
setTimeout(self.process1, 0, self, u);
else
setTimeout(self.process2, 0, self);
};
thumbnailer.prototype.process2 = function(self) {
self.canvas.width = self.dest.width;
self.canvas.height = self.dest.height;
self.ctx.drawImage(self.img, 0, 0, self.dest.width, self.dest.height);
self.src = self.ctx.getImageData(0, 0, self.dest.width, self.dest.height);
var idx, idx2;
for (var i = 0; i < self.dest.width; i++) {
for (var j = 0; j < self.dest.height; j++) {
idx = (j * self.dest.width + i) * 3;
idx2 = (j * self.dest.width + i) * 4;
self.src.data[idx2] = self.dest.data[idx];
self.src.data[idx2 + 1] = self.dest.data[idx + 1];
self.src.data[idx2 + 2] = self.dest.data[idx + 2];
}
}
self.ctx.putImageData(self.src, 0, 0);
self.canvas.style.display = "block";
};
...このような結果を出すことができるのです。
ということで、とりあえず、例の「修正版」をご紹介します。
img.onload = function() {
var canvas = document.createElement("canvas");
new thumbnailer(canvas, img, 188, 3); //this produces lanczos3
// but feel free to raise it up to 8. Your client will appreciate
// that the program makes full use of his machine.
document.body.appendChild(canvas);
};
さて、次はあなたのベストブラウザを並べて、どれがクライアントの血圧を上げる可能性が低いかを見てみましょう。
えーと、皮肉タグはどこだっけ?
(をベースにしている部分が多いので)。 Anrieff ギャラリージェネレーター もGPL2でカバーされるのでしょうか?分かりませんが)
† 実は、javascriptの制限により、マルチコアはサポートされていません。
関連
-
[解決済み] 解決済み】clearInterval()が動作しない [重複] [重複]
-
[解決済み】ある要素を別の要素に移動させるには?
-
[解決済み】ES6マップオブジェクトをソートすることは可能ですか?
-
[解決済み] HTML5のlocalStorageにオブジェクトを格納する方法は?
-
[解決済み] CSSでテキストや画像の背景を透明にするには?
-
[解決済み] 画像の横のテキストを縦に揃える?
-
[解決済み] アップロード前に画像をプレビューする
-
[解決済み] 再描画のためにキャンバスをクリアする方法
-
[解決済み] HTML5/Canvas/JavaScriptを使用してブラウザ内のスクリーンショットを撮影する
-
[解決済み】HTML5入力のプレースホルダの色をCSSで変更する。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】Uncaught ReferenceError: angular is not defined - AngularJSが動作しない。
-
[解決済み] Uncaught TypeError: 未定義のプロパティ 'top' を読み込めない
-
[解決済み] 解決済み】clearInterval()が動作しない [重複] [重複]
-
[解決済み】XMLパースエラー:ルート要素が見つからない コンソールの場所 FF
-
[解決済み] ローカルファイルを開くことができません - Chrome: ローカルリソースのロードが許可されていません
-
[解決済み】FirefoxでGoogle Maps V3をリモートで使用すると「googleが定義されていません」と表示される。
-
[解決済み】Kendo Observable Bindingと併用する場合、Kendo Switch Labelsを変更することは可能ですか?[Kendo-UI]です。
-
[解決済み】ES6マップオブジェクトをソートすることは可能ですか?
-
[解決済み】TypeError: AngularJSで未定義のプロパティ'get'を読み取れない
-
[解決済み] HTML5 Canvas Resize (Downscale) Image High Quality?