使用javascript画布调整图像大小(平稳)

问题描述 投票:72回答:7

我正在尝试使用画布调整某些图像的大小,但是我对如何使其平滑一无所知。在photoshop,浏览器等上。它们使用几种算法(例如,双三次,双线性),但我不知道这些算法是否内置在画布中。

这是我的小提琴:http://jsfiddle.net/EWupT/

var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width=300
canvas.height=234
ctx.drawImage(img, 0, 0, 300, 234);
document.body.appendChild(canvas);

第一个是正常尺寸的图像标签,第二个是画布。请注意,画布如何不那么光滑。如何获得“平滑度”?

javascript html image canvas html5-canvas
7个回答
118
投票

您可以使用降级以获得更好的结果。调整图像大小时,大多数浏览器似乎为use linear interpolation rather than bi-cubic

(<< [Update已在规范中添加了quality属性,imageSmoothingQuality仅在Chrome中可用。]

除非没有选择任何平滑或最接近的邻居,否则浏览器将在缩小图像后始终对图像进行插值,因为此功能用作低通滤波器以避免混叠。

[双线性使用2x2像素进行插值,而双三次使用4x4,因此,通过逐步进行操作,您可以在使用双线性插值时获得接近双三次的结果,如在所得图像中看到的。

imageSmoothingQuality
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var img = new Image();

img.onload = function () {

    // set size proportional to image
    canvas.height = canvas.width * (img.height / img.width);

    // step 1 - resize to 50%
    var oc = document.createElement('canvas'),
        octx = oc.getContext('2d');

    oc.width = img.width * 0.5;
    oc.height = img.height * 0.5;
    octx.drawImage(img, 0, 0, oc.width, oc.height);

    // step 2
    octx.drawImage(oc, 0, 0, oc.width * 0.5, oc.height * 0.5);

    // step 3, resize to final size
    ctx.drawImage(oc, 0, 0, oc.width * 0.5, oc.height * 0.5,
    0, 0, canvas.width, canvas.height);
}
img.src = "//i.imgur.com/SHo6Fub.jpg";
根据调整大小的剧烈程度,如果差异较小,可以跳过第2步。

在演示中,您可以看到新结果现在与图像元素非常相似。


17
投票
我创建了可重复使用的Angular服务,以处理对感兴趣的任何人的图像/画布的高质量缩放:<img src="//i.imgur.com/SHo6Fub.jpg" width="300" height="234"> <canvas id="canvas" width=300></canvas>

该服务包括两个解决方案,因为它们都有各自的优缺点。 lanczos卷积方法的质量较高,但代价是速度较慢,而逐步缩小的方法则可以产生合理的抗锯齿结果,并且速度明显更快。

示例用法:

https://gist.github.com/transitive-bullshit/37bac5e741eaec60e983


17
投票
因为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 }) }) 根本不正确(它仅在最后一步中使用原始图像)我用性能比较写了自己的小提琴:

Trung Le Nguyen Nhat's fiddle

基本上是:

FIDDLE


4
投票
我创建了一个库,可让您在保留所有颜色数据的同时降低任何百分比。

img.onload = function() { var canvas = document.createElement('canvas'), ctx = canvas.getContext("2d"), oc = document.createElement('canvas'), octx = oc.getContext('2d'); canvas.width = width; // destination canvas size canvas.height = canvas.width * img.height / img.width; var cur = { width: Math.floor(img.width * 0.5), height: Math.floor(img.height * 0.5) } oc.width = cur.width; oc.height = cur.height; octx.drawImage(img, 0, 0, cur.width, cur.height); while (cur.width * 0.5 > width) { cur = { width: Math.floor(cur.width * 0.5), height: Math.floor(cur.height * 0.5) }; octx.drawImage(oc, 0, 0, cur.width * 2, cur.height * 2, 0, 0, cur.width, cur.height); } ctx.drawImage(oc, 0, 0, cur.width, cur.height, 0, 0, canvas.width, canvas.height); }

您可以在浏览器中包含的文件。结果将看起来像photoshop或图像魔术,保留所有颜色数据,平均像素,而不是获取附近的像素并丢弃其他像素。它不使用公式来猜测平均值,而是使用精确的平均值。


4
投票
基于K3N的答案,我通常为任何人重写代码

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

更新JSFIDDLE演示

这里是我的var oc = document.createElement('canvas'), octx = oc.getContext('2d'); oc.width = img.width; oc.height = img.height; octx.drawImage(img, 0, 0); while (oc.width * 0.5 > width) { oc.width *= 0.5; oc.height *= 0.5; octx.drawImage(oc, 0, 0, oc.width, oc.height); } oc.width = width; oc.height = oc.width * img.height / img.width; octx.drawImage(img, 0, 0, oc.width, oc.height);

2
投票
虽然其中一些代码段简短且有效,但遵循和理解它们并非易事。

由于我不喜欢堆栈溢出的“复制-粘贴”,我希望开发人员了解他们将代码推送到软件中,希望您会发现以下有用。

DEMO:使用JS和HTML Canvas演示小提琴手调整图像大小。

您可能会找到3种不同的方法来进行此大小调整,这将有助于您了解代码的工作方式以及原因。

ONLINE DEMO

可以在GitHub项目中找到您可能想在代码中使用的全部演示代码和TypeScript方法的完整代码。

https://jsfiddle.net/1b68eLdr/93089/

这是最终代码:

https://github.com/eyalc4/ts-image-resizer


1
投票
我编写了小型js实用程序,用于在前端裁剪和调整图像大小。这是GitHub项目上的export class ImageTools { base64ResizedImage: string = null; constructor() { } ResizeImage(base64image: string, width: number = 1080, height: number = 1080) { let img = new Image(); img.src = base64image; img.onload = () => { // Check if the image require resize at all if(img.height <= height && img.width <= width) { this.base64ResizedImage = base64image; // TODO: Call method to do something with the resize image } else { // Make sure the width and height preserve the original aspect ratio and adjust if needed if(img.height > img.width) { width = Math.floor(height * (img.width / img.height)); } else { height = Math.floor(width * (img.height / img.width)); } let resizingCanvas: HTMLCanvasElement = document.createElement('canvas'); let resizingCanvasContext = resizingCanvas.getContext("2d"); // Start with original image size resizingCanvas.width = img.width; resizingCanvas.height = img.height; // Draw the original image on the (temp) resizing canvas resizingCanvasContext.drawImage(img, 0, 0, resizingCanvas.width, resizingCanvas.height); let curImageDimensions = { width: Math.floor(img.width), height: Math.floor(img.height) }; let halfImageDimensions = { width: null, height: null }; // Quickly reduce the dize by 50% each time in few iterations until the size is less then // 2x time the target size - the motivation for it, is to reduce the aliasing that would have been // created with direct reduction of very big image to small image while (curImageDimensions.width * 0.5 > width) { // Reduce the resizing canvas by half and refresh the image halfImageDimensions.width = Math.floor(curImageDimensions.width * 0.5); halfImageDimensions.height = Math.floor(curImageDimensions.height * 0.5); resizingCanvasContext.drawImage(resizingCanvas, 0, 0, curImageDimensions.width, curImageDimensions.height, 0, 0, halfImageDimensions.width, halfImageDimensions.height); curImageDimensions.width = halfImageDimensions.width; curImageDimensions.height = halfImageDimensions.height; } // Now do final resize for the resizingCanvas to meet the dimension requirments // directly to the output canvas, that will output the final image let outputCanvas: HTMLCanvasElement = document.createElement('canvas'); let outputCanvasContext = outputCanvas.getContext("2d"); outputCanvas.width = width; outputCanvas.height = height; outputCanvasContext.drawImage(resizingCanvas, 0, 0, curImageDimensions.width, curImageDimensions.height, 0, 0, width, height); // output the canvas pixels as an image. params: format, quality this.base64ResizedImage = outputCanvas.toDataURL('image/jpeg', 0.85); // TODO: Call method to do something with the resize image } }; }} 。您也可以从最终图像中获取斑点以发送它。

link

© www.soinside.com 2019 - 2024. All rights reserved.