在HTML5画布中调整图像大小

我试图在客户端使用javascript和画布元素创建一个缩略图,但当我缩小图像下来,它看起来很糟糕。它看起来好像在photoshop中缩小了大小,重新采样设置为“最近邻居”而不是双立方。我知道它可以让这个看起来正确,因为这个网站可以很好地使用画布。我尝试使用他们在“[源代码]”链接中显示的相同代码,但它看起来仍然很糟糕。我是不是遗漏了什么,什么需要设置的设置之类的?

编辑:

我正在调整一张jpg图片的大小。我试过在链接的网站和photoshop中调整相同的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:

看来我错了,链接网站并没有做任何更好的工作缩小图像。我尝试了其他建议的方法,没有一个看起来更好。这就是不同方法的结果:

ps:

alt text

帆布:

alt text

使用图像渲染:optimizeQuality设置并按宽度/高度缩放:

alt text

使用-moz-transform设置和缩放:

alt text

Canvas在pixastic上调整大小:

alt text

我猜这意味着firefox没有像它应该的那样使用双三次抽样。我只能等他们真的加进去了。

EDIT3:

原始图片 .

311976 次浏览

如果你只是想调整图像的大小,我建议用CSS设置图像的widthheight。这里有一个简单的例子:

.small-image {
width: 100px;
height: 100px;
}

注意,heightwidth也可以使用JavaScript设置。下面是快速代码示例:

var img = document.getElement("my-image");
img.style.width = 100 + "px";  // Make sure you add the "px" to the end,
img.style.height = 100 + "px"; // otherwise you'll confuse IE

此外,为了确保调整大小的图像看起来不错,在图像选择器中添加以下css规则:

据我所知,除了IE之外,所有浏览器都默认使用双三次算法来调整图像大小,所以你调整后的图像在Firefox和Chrome中应该看起来不错。

如果设置css widthheight不起作用,你可能想要使用css transform:

如果出于某种原因你需要要使用画布,请注意有两种方法可以调整图像的大小:通过css调整画布的大小或以较小的尺寸绘制图像。

更多细节参见这个问题

我通过右键单击firefox中的canvas元素并另存为来获得这张图像。

alt text

var img = new Image();
img.onload = function () {
console.debug(this.width,this.height);
var canvas = document.createElement('canvas'), ctx;
canvas.width = 188;
canvas.height = 150;
document.body.appendChild(canvas);
ctx = canvas.getContext('2d');
ctx.drawImage(img,0,0,188,150);
};
img.src = 'original.jpg';

不管怎样,这是你的例子的“固定”版本:

var img = new Image();
// added cause it wasnt defined
var canvas = document.createElement("canvas");
document.body.appendChild(canvas);


var ctx = canvas.getContext("2d");
var canvasCopy = document.createElement("canvas");
// adding it to the body


document.body.appendChild(canvasCopy);


var copyContext = canvasCopy.getContext("2d");


img.onload = function()
{
var ratio = 1;


// defining cause it wasnt
var maxWidth = 188,
maxHeight = 150;


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;
// the line to change
// ctx.drawImage(canvasCopy, 0, 0, canvasCopy.width, canvasCopy.height, 0, 0, canvas.width, canvas.height);
// the method signature you are using is for slicing
ctx.drawImage(canvasCopy, 0, 0, canvas.width, canvas.height);
};


// changed for example
img.src = 'original.jpg';

所以我发现了一些有趣的东西,在使用画布时可能会有所帮助:

要单独调整画布控件的大小,需要使用height=""width=""属性(或canvas.width/canvas.height元素)。如果你使用CSS来调整画布的大小,它实际上会拉伸(即:调整大小)画布的内容以适应整个画布(而不是简单地增加或减少画布的面积)。

尝试将图像绘制到画布控件中,并将height和width属性设置为图像的大小,然后使用CSS将画布调整为您想要的大小,这是值得一试的。也许这将使用不同的调整大小算法。

还应该注意的是,canvas在不同浏览器(甚至不同浏览器的不同版本)中具有不同的效果。在浏览器中使用的算法和技术可能会随着时间的推移而改变(特别是Firefox 4和Chrome 6很快就会出来,这将非常强调画布渲染性能)。

此外,您可能也想尝试一下SVG,因为它可能也使用了不同的算法。

祝你好运!

那么,如果所有的浏览器(实际上,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";
};

...用它你可以产生这样的结果!

img717.imageshack.us/img717/8910/lanczos358.png

不管怎样,这是你的例子的“固定”版本:

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 Gallery Generator它也被GPL2覆盖吗?我不知道)

实际上由于javascript的限制,不支持多核。

我强烈建议你检查这个链接并确保它被设置为true。

控制图像缩放行为

在Gecko 1.9.2中引入 / Thunderbird 3.1 / Fennec 1.0)

壁虎1.9.2介绍 mozImageSmoothingEnabled属性 canvas元素;如果这个布尔值 Value为false,图像不会为false 缩放时平滑。这个性质是 默认为True。看待plainprint ?< / p >

  1. 残雪。mozImageSmoothingEnabled = false;

我知道这是一个老话题,但它可能对像我这样的人有用,几个月后,我们第一次遇到这个问题。

这里有一些代码,可以在每次重新加载图像时调整图像的大小。我知道这根本不是最优的,但我提供它作为概念的证明。

另外,很抱歉使用jQuery来做简单的选择器,但我觉得语法太舒服了。

$(document).on('ready', createImage);
$(window).on('resize', createImage);


var createImage = function(){
var canvas = document.getElementById('myCanvas');
canvas.width = window.innerWidth || $(window).width();
canvas.height = window.innerHeight || $(window).height();
var ctx = canvas.getContext('2d');
img = new Image();
img.addEventListener('load', function () {
ctx.drawImage(this, 0, 0, w, h);
});
img.src = 'http://www.ruinvalor.com/Telanor/images/original.jpg';
};
html, body{
height: 100%;
width: 100%;
margin: 0;
padding: 0;
background: #000;
}
canvas{
position: absolute;
left: 0;
top: 0;
z-index: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<head>
<meta charset="utf-8" />
<title>Canvas Resize</title>
</head>
<body>
<canvas id="myCanvas"></canvas>
</body>
</html>

我的createImage函数在文档加载时被调用一次,之后每次窗口接收到调整大小事件时都被调用。

我在Mac电脑上的Chrome 6和Firefox 3.6中进行了测试。这种“技术”对处理器的消耗就像夏天的冰淇淋一样,但它确实奏效了。

为了调整图像的宽度小于原始,我使用:

    function resize2(i) {
var cc = document.createElement("canvas");
cc.width = i.width / 2;
cc.height = i.height / 2;
var ctx = cc.getContext("2d");
ctx.drawImage(i, 0, 0, cc.width, cc.height);
return cc;
}
var cc = img;
while (cc.width > 64 * 2) {
cc = resize2(cc);
}
// .. than drawImage(cc, .... )

它工作=)。

我刚刚运行了一个并排比较的页面,除非最近发生了一些变化,否则我看不到更好的缩小(缩放)使用canvas vs.简单的css。我在FF6 Mac OSX 10.7中进行了测试。和原版相比还是有点软。

然而,我确实偶然发现了一些确实产生巨大差异的东西,那就是在支持画布的浏览器中使用图像过滤器。实际上,你可以像在Photoshop中一样对图像进行模糊、锐化、饱和度、纹波、灰度等操作。

然后我发现了一个很棒的jQuery插件,使这些过滤器的应用程序一个快照: http://codecanyon.net/item/jsmanipulate-jquery-image-manipulation-plugin/428234 < / p >

我只是在调整图像大小后应用锐化滤镜,这应该会给你想要的效果。我甚至不需要使用canvas元素。

我已经提出了一些算法在html画布像素数组上做图像插值,可能在这里有用:

https://web.archive.org/web/20170104190425/http://jsperf.com:80/pixel-interpolation/2

这些可以复制/粘贴,并可以在web worker中使用来调整图像大小(或任何其他需要插值的操作-我正在使用它们来修饰图像)。

我没有添加上面的lanczos的东西,所以如果你愿意,可以随意添加作为比较。

这是一个javascript函数改编自@Telanor的代码。当将图像base64作为第一个参数传递给函数时,它将返回调整后图像的base64。maxWidth和maxHeight是可选的。

function thumbnail(base64, maxWidth, maxHeight) {


// Max size for thumbnail
if(typeof(maxWidth) === 'undefined') var maxWidth = 500;
if(typeof(maxHeight) === 'undefined') var maxHeight = 500;


// Create and initialize two canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
var canvasCopy = document.createElement("canvas");
var copyContext = canvasCopy.getContext("2d");


// Create original image
var img = new Image();
img.src = base64;


// Determine new ratio based on max size
var ratio = 1;
if(img.width > maxWidth)
ratio = maxWidth / img.width;
else if(img.height > maxHeight)
ratio = maxHeight / img.height;


// Draw original image in second canvas
canvasCopy.width = img.width;
canvasCopy.height = img.height;
copyContext.drawImage(img, 0, 0);


// Copy and resize second canvas to first canvas
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);


return canvas.toDataURL();


}

谢谢@syockit的精彩回答。然而,我不得不重新格式化如下使它工作。可能是由于DOM扫描问题:

$(document).ready(function () {


$('img').on("load", clickA);
function clickA() {
var img = this;
var canvas = document.createElement("canvas");
new thumbnailer(canvas, img, 50, 3);
document.body.appendChild(canvas);
}


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(process1, 0, this, 0);
}


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


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(process1, 0, self, u);
else
setTimeout(process2, 0, self);
};


process2 = function (self) {
self.canvas.width = self.dest.width;
self.canvas.height = self.dest.height;
self.ctx.drawImage(self.img, 0, 0);
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";
}
});
快速图像调整/重采样算法使用埃尔米特过滤器与JavaScript。支持透明,给予优质。预览:

enter image description here

更新: 2.0版本添加到GitHub(更快,网络工作者+可转移对象)。终于我让它工作了!

Git: https://github.com/viliusle/Hermite-resize
演示:http://viliusle.github.io/miniPaint/ < / p >

/**
* Hermite resize - fast image resize/resample using Hermite filter. 1 cpu version!
*
* @param {HtmlElement} canvas
* @param {int} width
* @param {int} height
* @param {boolean} resize_canvas if true, canvas will be resized. Optional.
*/
function resample_single(canvas, width, height, resize_canvas) {
var width_source = canvas.width;
var height_source = canvas.height;
width = Math.round(width);
height = Math.round(height);


var ratio_w = width_source / width;
var ratio_h = height_source / height;
var ratio_w_half = Math.ceil(ratio_w / 2);
var ratio_h_half = Math.ceil(ratio_h / 2);


var ctx = canvas.getContext("2d");
var img = ctx.getImageData(0, 0, width_source, height_source);
var img2 = ctx.createImageData(width, height);
var data = img.data;
var data2 = img2.data;


for (var j = 0; j < height; j++) {
for (var i = 0; i < width; i++) {
var x2 = (i + j * width) * 4;
var weight = 0;
var weights = 0;
var weights_alpha = 0;
var gx_r = 0;
var gx_g = 0;
var gx_b = 0;
var gx_a = 0;
var center_y = (j + 0.5) * ratio_h;
var yy_start = Math.floor(j * ratio_h);
var yy_stop = Math.ceil((j + 1) * ratio_h);
for (var yy = yy_start; yy < yy_stop; yy++) {
var dy = Math.abs(center_y - (yy + 0.5)) / ratio_h_half;
var center_x = (i + 0.5) * ratio_w;
var w0 = dy * dy; //pre-calc part of w
var xx_start = Math.floor(i * ratio_w);
var xx_stop = Math.ceil((i + 1) * ratio_w);
for (var xx = xx_start; xx < xx_stop; xx++) {
var dx = Math.abs(center_x - (xx + 0.5)) / ratio_w_half;
var w = Math.sqrt(w0 + dx * dx);
if (w >= 1) {
//pixel too far
continue;
}
//hermite filter
weight = 2 * w * w * w - 3 * w * w + 1;
var pos_x = 4 * (xx + yy * width_source);
//alpha
gx_a += weight * data[pos_x + 3];
weights_alpha += weight;
//colors
if (data[pos_x + 3] < 255)
weight = weight * data[pos_x + 3] / 250;
gx_r += weight * data[pos_x];
gx_g += weight * data[pos_x + 1];
gx_b += weight * data[pos_x + 2];
weights += weight;
}
}
data2[x2] = gx_r / weights;
data2[x2 + 1] = gx_g / weights;
data2[x2 + 2] = gx_b / weights;
data2[x2 + 3] = gx_a / weights_alpha;
}
}
//clear and resize canvas
if (resize_canvas === true) {
canvas.width = width;
canvas.height = height;
} else {
ctx.clearRect(0, 0, width_source, height_source);
}


//draw
ctx.putImageData(img2, 0, 0);
}

我有一种感觉,我写的模块将产生类似于photoshop的结果,因为它通过平均颜色数据来保存它们,而不是应用算法。它有点慢,但对我来说是最好的,因为它保留了所有的颜色数据。

https://github.com/danschumann/limby-resize/blob/master/lib/canvas_resize.js

它不会选取最近的邻居并删除其他像素,也不会对一组进行抽样并随机取平均值。它取每个源像素输出到目标像素的精确比例。源点的平均像素颜色就是目标点的平均像素颜色,我认为其他公式不是这样的。

如何使用的例子在底部 https://github.com/danschumann/limby-resize < / p >

2018年10月更新:这些天我的例子比其他任何东西都更学术。Webgl几乎是100%,所以你最好用它来调整大小,以产生类似的结果,但更快。我相信PICA.js就是这么做的。- - - - - -

还在寻找另一个简单的解决方案吗?

var img=document.createElement('img');
img.src=canvas.toDataURL();
$(img).css("background", backgroundColor);
$(img).width(settings.width);
$(img).height(settings.height);

这个解决方案将使用浏览器的调整大小算法!:)

其中一些解决方案的问题是,它们直接访问像素数据并通过它进行循环以执行下采样。根据图像的大小,这可能会非常消耗资源,最好使用浏览器的内部算法。

drawImage ()函数使用线性插值,最近邻重采样方法。当您没有将大小调整到原来大小的一半以上时,效果很好

如果循环一次只调整最大大小的一半,结果会非常好,而且比访问像素数据快得多。

这个函数每次采样到一半,直到达到所需的大小:

  function resize_image( src, dst, type, quality ) {
var tmp = new Image(),
canvas, context, cW, cH;


type = type || 'image/jpeg';
quality = quality || 0.92;


cW = src.naturalWidth;
cH = src.naturalHeight;


tmp.src = src.src;
tmp.onload = function() {


canvas = document.createElement( 'canvas' );


cW /= 2;
cH /= 2;


if ( cW < src.width ) cW = src.width;
if ( cH < src.height ) cH = src.height;


canvas.width = cW;
canvas.height = cH;
context = canvas.getContext( '2d' );
context.drawImage( tmp, 0, 0, cW, cH );


dst.src = canvas.toDataURL( type, quality );


if ( cW <= src.width || cH <= src.height )
return;


tmp.src = dst.src;
}


}
// The images sent as parameters can be in the DOM or be image objects
resize_image( $( '#original' )[0], $( '#smaller' )[0] );

感谢这篇文章

我把@syockit的答案和降格方法转换成了一个可重用的Angular服务,有兴趣的人可以使用:https://gist.github.com/fisch0920/37bac5e741eaec60e983

我包括了这两种解决方案,因为它们都有各自的优点和缺点。lanczos卷积方法的质量更高,但代价是速度较慢,而逐步降尺度方法产生了合理的抗锯齿结果,而且速度明显更快。

使用示例:

angular.module('demo').controller('ExampleCtrl', function (imageService) {
// EXAMPLE USAGE
// NOTE: it's bad practice to access the DOM inside a controller,
// but this is just to show the example usage.


// resize by lanczos-sinc filter
imageService.resize($('#myimg')[0], 256, 256)
.then(function (resizedImage) {
// do something with resized image
})


// resize by stepping down image size in increments of 2x
imageService.resizeStep($('#myimg')[0], 256, 256)
.then(function (resizedImage) {
// do something with resized image
})
})

尝试异食癖 -这是一个高度优化的大小调整器,具有可选择的算法。看到演示

例如,第一个帖子的原始图像用Lanczos过滤器和3px窗口在120ms内调整大小,或者用Box过滤器和0.5px窗口在60ms内调整大小。对于17mb的巨大图像,5000x3000px的大小调整在台式机上需要1秒,在手机上需要3秒。

所有调整大小的原则都在这篇文章中描述得很好,异食癖并没有增加火箭科学。但是它针对现代jit进行了很好的优化,并且可以开箱即用(通过npm或bower)。此外,它使用网络工作者,以避免接口冻结。

我还计划很快添加不锐利的掩模支持,因为它在降级后非常有用。

快速和简单的Javascript图像调整器:

https://github.com/calvintwr/blitz-hermite-resize

const blitz = Blitz.create()


/* Promise */
blitz({
source: DOM Image/DOM Canvas/jQuery/DataURL/File,
width: 400,
height: 600
}).then(output => {
// handle output
})catch(error => {
// handle error
})


/* Await */
let resized = await blizt({...})


/* Old school callback */
const blitz = Blitz.create('callback')
blitz({...}, function(output) {
// run your callback.
})

历史

这是经过多轮研究、阅读和尝试后得出的结论。

调整器算法使用@ViliusL的Hermite脚本(Hermite调整器确实是最快的,并且提供了相当好的输出)。扩展了您需要的功能。

fork 1 worker来调整大小,这样它就不会在调整大小时冻结你的浏览器,不像其他所有的JS调整器。

我想从答案中得到一些定义良好的函数,所以最后得到了这些,我希望对其他人也有用,

function getImageFromLink(link) {
return new Promise(function (resolve) {
var image = new Image();
image.onload = function () { resolve(image); };
image.src = link;
});
}


function resizeImageToBlob(image, width, height, mime) {
return new Promise(function (resolve) {
var canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
canvas.getContext('2d').drawImage(image, 0, 0, width, height);
return canvas.toBlob(resolve, mime);
});
}


getImageFromLink(location.href).then(function (image) {
// calculate these based on the original size
var width = image.width / 4;
var height = image.height / 4;
return resizeImageToBlob(image, width, height, 'image/jpeg');
}).then(function (blob) {
// Do something with the result Blob object
document.querySelector('img').src = URL.createObjectURL(blob);
});

为了测试这个,在一个标签中打开的图像上运行它。