rcp html5,javascript - Resizing an image in an HTML5 canvas - Stack Overflow

这篇博客介绍了一种方法,通过JavaScript自行实现高质量的图像缩略图生成算法,特别是针对浏览器内核的不足。作者展示了如何利用Lanczos重采样技术,并提供了一个示例代码,创建了一个thumbnailer类,能够根据指定的缩放比例和核半径产生高清晰度的缩略图。此代码基于Web3.0和HTML5标准,充分利用现代浏览器的性能,如优化的JavaScript JIT编译器和多核处理器。
摘要由CSDN通过智能技术生成

So what do you do if all the browsers (actually, Chrome 5 gave me quite good one) won't give you good enough resampling quality? You implement them yourself then! Oh come on, we're entering the new age of Web 3.0, HTML5 compliant browsers, super optimized JIT javascript compilers, multi-core(†) machines, with tons of memory, what are you afraid of? Hey, there's the word java in javascript, so that should guarantee the performance, right? Behold, the thumbnail generating code:

// 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";

};

...with which you can produce results like these!

dpATi.png

so anyway, here is a 'fixed' version of your example:

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);

};

Now it's time to pit your best browsers out there and see which one will least likely increase your client's blood pressure!

Umm, where's my sarcasm tag?

(since many parts of the code is based on Anrieff Gallery Generator is it also covered under GPL2? I don't know)

† actually due to limitation of javascript, multi-core is not supported.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值