我正在尝试使用 javascript 和画布元素在客户端创建缩略图,但是当我缩小图像时,它看起来很糟糕。它看起来好像在 Photoshop 中缩小了尺寸,将重采样设置为“最近邻”而不是双三次。我知道它可以使它看起来正确,因为 this site 也可以使用画布很好地做到这一点。我尝试使用与“[Source]”链接中显示的相同的代码,但它看起来仍然很糟糕。有什么我遗漏的东西,需要设置的一些设置吗?
编辑:
我正在尝试调整 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;
}
编辑2:
似乎我弄错了,链接的网站在缩小图像尺寸方面并没有做得更好。我尝试了建议的其他方法,但没有一个看起来更好。这就是不同方法的结果:
Photoshop:
https://i.stack.imgur.com/K6ztq.png
帆布:
https://i.stack.imgur.com/nD3FJ.png
带有图像渲染的图像:optimizeQuality 设置并按宽度/高度缩放:
https://i.stack.imgur.com/I6RkV.png
带有图像渲染的图像:optimizeQuality 设置并使用 -moz-transform 进行缩放:
https://i.stack.imgur.com/ZWiVC.png
在 pixastic 上调整画布大小:
https://i.stack.imgur.com/PEsYM.png
我想这意味着 Firefox 没有像预期的那样使用双三次采样。我只需要等到他们真正添加它。
编辑3:
那么,如果所有浏览器(实际上,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";
};
...你可以用它产生这样的结果!
https://i.stack.imgur.com/dpATi.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 的限制,不支持多核。
https://i.stack.imgur.com/oek4l.png
更新:在 GitHub 上添加了 2.0 版(更快,网络工作者 + 可转移对象)。最后我让它工作了!
Git:https://github.com/viliusle/Hermite-resize
演示:http://viliusle.github.io/miniPaint/
/**
* 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);
}
试试 pica - 这是一个高度优化的大小调整器,具有可选的算法。见demo。
例如,使用 Lanczos 过滤器和 3px 窗口或 60ms 使用 Box 过滤器和 0.5px 窗口调整第一篇文章的原始图像的大小。对于巨大的 17mb 图像 5000x3000px 调整大小在桌面上需要大约 1 秒,在移动设备上需要 3 秒。
在这个线程中,所有调整大小的原则都得到了很好的描述,而且 pica 没有添加火箭科学。但它针对现代 JIT-s 进行了很好的优化,并且可以开箱即用(通过 npm 或 bower)。此外,它在可用时使用网络工作者以避免界面冻结。
我还计划很快添加非锐化蒙版支持,因为它在缩小后非常有用。
我知道这是一个旧线程,但它可能对像我这样的一些人在几个月后第一次遇到这个问题时有用。
这是一些每次重新加载图像时都会调整图像大小的代码。我知道这根本不是最优的,但我提供它作为概念证明。
另外,很抱歉将 jQuery 用于简单的选择器,但我觉得语法太舒服了。
$(document).on('ready', createImage); $(window).on('resize', createImage); var createImage = function(){ var canvas = document.getElementById('myCanvas'); canvas.width = window.innerWidth || $(窗口).width(); canvas.height = window.innerHeight || $(窗口).height(); var ctx = canvas.getContext('2d'); img = 新图像(); img.addEventListener('load', function () { ctx.drawImage(this, 0, 0, w, h); }); img.src = 'http://www.ruinvalor.com/Telanor/images/original.jpg'; }; html, body{ 高度: 100%;宽度:100%;边距:0;填充:0;背景:#000; } 画布{ 位置:绝对;左:0;顶部:0; z-index:0; }
我的 createImage 函数在加载文档时调用一次,之后每次窗口接收到调整大小事件时调用它。
我在 Mac 上的 Chrome 6 和 Firefox 3.6 中对其进行了测试。这种“技术”就像夏天吃冰淇淋一样吃处理器,但它确实成功了。
我已经提出了一些算法来对 html 画布像素数组进行图像插值,这可能在这里有用:
https://web.archive.org/web/20170104190425/http://jsperf.com:80/pixel-interpolation/2
这些可以复制/粘贴,并且可以在网络工作者内部使用来调整图像大小(或任何其他需要插值的操作——我现在正在使用它们来去除图像)。
我没有在上面添加 lanczos 的东西,所以如果你愿意,可以随意添加它作为比较。
这是一个改编自@Telanor 代码的javascript 函数。将图像 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();
}
我强烈建议您检查 this link 并确保它设置为 true。
控制图像缩放行为 Gecko 1.9.2 中引入(Firefox 3.6 / Thunderbird 3.1 / Fennec 1.0) Gecko 1.9.2 向 canvas 元素引入了 mozImageSmoothingEnabled 属性;如果此布尔值为 false,则缩放时不会平滑图像。此属性默认为 true。查看普通版? cx.mozImageSmoothingEnabled = false;
如果您只是想调整图像大小,我建议您使用 CSS 设置图像的 width
和 height
。这是一个简单的例子:
.small-image {
width: 100px;
height: 100px;
}
请注意,也可以使用 JavaScript 设置 height
和 width
。这是快速代码示例:
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 规则添加到图像选择器:
-ms-interpolation-mode: 双三次:在 IE7 中引入
图像渲染:optimizeQuality:在 FireFox 3.6 中引入
据我所知,除了 IE 之外的所有浏览器都默认使用双三次算法来调整图像大小,因此您调整大小的图像在 Firefox 和 Chrome 中应该看起来不错。
如果设置 css width
和 height
不起作用,您可能需要使用 css transform
:
-moz 变换:比例(sx [,sy])
-webkit-transform:scale(sx[, sy])
如果出于某种原因需要使用画布,请注意有两种方法可以调整图像的大小:使用 css 调整画布的大小或以较小的尺寸绘制图像。
有关详细信息,请参阅 this question。
我通过右键单击Firefox中的画布元素并另存为来获得此图像。
https://i.stack.imgur.com/E5GfF.png
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';
为了调整宽度小于原始图像的大小,我使用:
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, .... )
它有效=)。
我有一种感觉,我编写的模块会产生与 Photoshop 相似的结果,因为它通过对颜色数据进行平均来保留颜色数据,而不是应用算法。这有点慢,但对我来说这是最好的,因为它保留了所有的颜色数据。
https://github.com/danschumann/limby-resize/blob/master/lib/canvas_resize.js
它不会采用最近的邻居并丢弃其他像素,也不会对一组进行采样并进行随机平均。它采用每个源像素应输出到目标像素的确切比例。源中的平均像素颜色将是目标中的平均像素颜色,我认为这些其他公式不会。
https://github.com/danschumann/limby-resize底部有一个如何使用的例子
2018 年 10 月更新:这些天我的例子比其他任何东西都更具学术性。 Webgl 几乎是 100%,所以你最好调整大小以产生类似的结果,但速度更快。我相信 PICA.js 会这样做。 –
其中一些解决方案的问题在于它们直接访问像素数据并循环通过它来执行下采样。根据图像的大小,这可能会占用大量资源,最好使用浏览器的内部算法。
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] );
归功于 this post
所以我不久前在使用画布时发现了一些有趣的东西,这可能会有所帮助:
要自行调整画布控件的大小,您需要使用 height=""
和 width=""
属性(或 canvas.width
/canvas.height
元素)。如果您使用 CSS 调整画布大小,它实际上会拉伸(即:调整大小)画布的内容以适应整个画布(而不是简单地增加或减少画布的面积。
尝试将图像绘制到画布控件中,并将高度和宽度属性设置为图像的大小,然后使用 CSS 将画布调整为您正在寻找的大小,这是值得一试的。也许这会使用不同的调整大小算法。
还需要注意的是,canvas在不同的浏览器(甚至不同浏览器的不同版本)下的效果是不一样的。浏览器中使用的算法和技术可能会随着时间而改变(尤其是 Firefox 4 和 Chrome 6 即将推出,这将非常重视画布渲染性能)。
此外,您可能还想试一试 SVG,因为它也可能使用不同的算法。
祝你好运!
快速简单的 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.
})
历史
这确实是经过多轮研究、阅读和尝试。
resizer 算法使用@ViliusL 的 Hermite 脚本(Hermite resizer 确实是最快的并且提供了相当好的输出)。扩展了您需要的功能。
与所有其他 JS 调整大小不同,派生 1 个工作人员来调整大小,以便在调整大小时不会冻结您的浏览器。
我将@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
})
})
感谢@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";
}
});
我希望这里的答案中有一些定义明确的函数,所以最终得到了这些希望对其他人也有用的函数,
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);
});
只是为了测试它在选项卡中打开的图像上运行它。
我刚刚运行了一页并排比较,除非最近发生了一些变化,否则我看不出使用画布与简单 css 相比没有更好的缩小(缩放)。我在 FF6 Mac OSX 10.7 中进行了测试。与原版相比,仍然略显柔软。
然而,我确实偶然发现了一些确实产生巨大影响的东西,那就是在支持画布的浏览器中使用图像过滤器。您实际上可以像在 Photoshop 中一样使用模糊、锐化、饱和度、波纹、灰度等来处理图像。
然后我发现了一个很棒的 jQuery 插件,它可以让这些过滤器的应用变得轻而易举:http://codecanyon.net/item/jsmanipulate-jquery-image-manipulation-plugin/428234
我只是在调整图像大小后立即应用锐化滤镜,这应该会给你想要的效果。我什至不必使用画布元素。
寻找另一个伟大的简单解决方案?
var img=document.createElement('img');
img.src=canvas.toDataURL();
$(img).css("background", backgroundColor);
$(img).width(settings.width);
$(img).height(settings.height);
此解决方案将使用浏览器的调整大小算法! :)
不定期副业成功案例分享