Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
443 views
in Technique[技术] by (71.8m points)

javascript - 调整HTML5画布中图像的大小(Resizing an image in an HTML5 canvas)

I'm trying to create a thumbnail image on the client side using javascript and a canvas element, but when I shrink the image down, it looks terrible.(我正在尝试使用javascript和canvas元素在客户端创建缩略图,但是当我缩小图像时,它看起来很糟糕。)

It looks as if it was downsized in photoshop with the resampling set to 'Nearest Neighbor' instead of Bicubic.(看起来好像是在Photoshop中缩小了尺寸,将重采样设置为“最近的邻居”而不是Bicubic。) I know its possible to get this to look right, because this site can do it just fine using a canvas as well.(我知道有可能使它看起来正确,因为该站点也可以使用画布来完成它。) I've tried using the same code they do as shown in the "[Source]" link, but it still looks terrible.(我尝试使用与[[Source]]链接中所示相同的代码,但是它看起来仍然很糟糕。) Is there something I'm missing, some setting that needs to be set or something?(是否有我所缺少的东西,需要设置的设置或其他东西?)

EDIT:(编辑:)

I'm trying to resize a jpg.(我正在尝试调整jpg的大小。)

I have tried resizing the same jpg on the linked site and in photoshop, and it looks fine when downsized.(我尝试在链接的网站和photoshop中调整相同jpg的大小,缩小尺寸后看起来不错。)

Here is the relevant code:(以下是相关代码:)

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:(编辑2:)

Seems I was mistaken, the linked website wasn't doing any better of a job of downsizing the image.(似乎我弄错了,链接的网站在缩小图像尺寸方面做得更好。)

I tried the other methods suggested and none of them look any better.(我尝试了建议的其他方法,但没有一个看起来更好。) This is what the different methods resulted in:(这是不同方法导致的结果:)

Photoshop:(Photoshop:)

替代文字

Canvas:(帆布:)

替代文字

Image with image-rendering: optimizeQuality set and scaled with width/height:(具有图像渲染的图像:optimizeQuality设置并随宽度/高度缩放:)

替代文字

Image with image-rendering: optimizeQuality set and scaled with -moz-transform:(具有图像渲染的图像:optimizeQuality设置并使用-moz-transform缩放:)

替代文字

Canvas resize on pixastic:(画布在像素上调整大小:)

替代文字

I guess this means firefox isn't using bicubic sampling like its supposed to.(我猜这意味着Firefox并未像预期的那样使用三次三次采样。)

I'll just have to wait until they actually add it.(我只需要等待,直到他们实际添加它。)

EDIT3:(编辑3:)

Original Image(原始图片)

  ask by Telanor translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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?(那么,如果所有浏览器(实际上,Chrome 5给我提供了很好的浏览器)都无法为您提供足够好的重采样质量,您该怎么办?)

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?(哦,来吧,我们正在进入Web 3.0的新时代,符合HTML5的浏览器,超级优化的JIT javascript编译器,具有大量内存的多核(?)机器,您担心什么?) Hey, there's the word java in javascript, so that should guarantee the performance, right?(嘿,javascript中有java一词,因此应该可以保证性能,对吗?) 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!(...您可以用它产生这样的结果!)

img717.imageshack.us/img717/8910/lanczos358.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 dunno)((由于代码的许多部分都基于Anrieff Gallery GeneratorGPL2也涵盖了它吗?我不知道))

? actually due to limitation of javascript, multi-core is not supported.(? 实际上由于javascript的限制,不支持多核。)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...