【问题标题】:HTML5 - Poor image quality when resizing canvasHTML5 - 调整画布大小时图像质量差
【发布时间】:2012-12-05 16:51:03
【问题描述】:

我正在制作和上传带有客户端图像大小的页面(使用 HTML5 画布)。一切正常,但问题是图像质量不是很好。

Here is a link 到(正在进行的)照片库,其中包含我的调整大小/上传代码生成的图像。

你明白我说的质量差是什么意思吗?许多锯齿状边缘,尤其是在缩略图图像上。有关如何解决此问题的任何想法?

这是我用于生成缩略图的 javascript:

img.onload = function()
{
   var canvasWidth = 150;
   var canvasHeight = 150;
   var Rz = resizeCanvasSmall(img,canvasID,canvasWidth,canvasHeight);

   ctx.drawImage(img,Rz[0],Rz[1],Rz[2],Rz[3],Rz[4],Rz[5],Rz[6],Rz[7]);
   dataurl = canvas.toDataURL("image/jpeg",0.8);  // File type and quality (0.0->1.0)
   UploadFile();
}


// Function to resize canvas (for thumbnail images)
// img = image object, canvas = canvas element ID
function resizeCanvasSmall(img,canvas,width,height)
{
var sx; //The x coordinate where to start clipping
var sy; //The y coordinate where to start clipping
var swidth; //The width of the clipped image
var sheight; //The height of the clipped image

var aspectRatio = width / height;

if (img.width > img.height) // If landscape
{
    sheight = img.height;
    swidth = img.height * aspectRatio;
    sy = 0;
    sx = (img.width - swidth) / 2;
}
else //If portrait
{
    swidth = img.width;
    sheight = img.width / aspectRatio;
    sx = 0;
    sy = (img.height - sheight) / 2;
}

document.getElementById(canvas).width = width;
document.getElementById(canvas).height = height;

return [sx,sy,swidth,sheight,0,0,width,height];
}

【问题讨论】:

  • 我在图像中注意到的第一件事 - 调整大小不合适。我的意思是原始图像(W1,H1)缩略图(W2,H2)。如果 (W1/W2 == H1/H2) 你会得到更好的结果
  • 这个标准没有指定drawImage使用的缩放算法,所以浏览器可以使用任何他们想要的。当您需要高级图像过滤(例如 lanczos 上的双三次、sinc)时,您必须自己实现它们。
  • 你可能是对的 (W1/W2 == H1/H2) @Joddy。我猜如果原始图像是 3241x2321 像素(例如),那么当您将图像缩小时,您将无法完美地保持纵横比。我会尝试编写一些代码,首先将图像剪辑成可以缩小的大小......如果它有效,会告诉你。
  • Jcrop 也是另一个不错的图片上传 jQuery 插件。 deepliquid.com/content/Jcrop.html

标签: javascript html canvas


【解决方案1】:

我不确定幕后使用的是什么,但我一直认为Processing.js has a pretty decent looking image resize。该文档有一些示例用法。 (更新:查看调整大小的代码,它看起来与您正在执行的操作类似。除了它从一张图像中获取数据并将其移动到另一张图像。)

调整大小时要注意的另一件事是,如果可能,始终将图像大小减半,以便像素排列得更好。理想调整大小的示例是 50%、25% 等。

【讨论】:

  • 感谢您推荐 Processing.js。我要去看看它。我已经尝试了我现在能想到的一切,只使用 HTML5 和画布元素,但我尝试的任何方法都完全没有区别。我猜规范只是不符合图像调整大小?我希望我错了,因为那将是一种耻辱。
【解决方案2】:

调整大量大小的一般规则是进行 2 次方的跳跃,以减少混叠伪影,然后在余下的过程中只进行最后一次调整大小。例如:如果您需要将 1000 像素缩小到 68 像素,则将其缩小到 500 像素,然后是 250 像素,然后是 125 像素,然后是 68 像素。在最后一个之前,它始终是 2 的幂。

此外,您应该保留纵横比,否则您会在对角线处获得时髦的锯齿。如果您需要来自非方形源图像的方形缩略图,则在尽可能接近目标方形的同时缩小尺寸,同时仍然更大,然后在中心裁剪它。 (或者变小并填充它)。您必须不惜一切代价保持纵横比。

要获得比我所描述的更好的结果,您必须实现自己的大小调整算法,这将慢得多(因为它们将在 JS 中而不是优化的本机代码中)。跳入 WebGL 也可能是一种选择。

【讨论】:

  • 它仍然是最近的邻居并且会发生颜色丢失,它可能看起来更少。
【解决方案3】:

http://output.jsbin.com/palota/1/

我制作了一个画布调整大小插件。其中一个文件可以包含在前端。它逐个像素地进行。它不是抓取附近的像素,而是对颜色进行平均,因此从原始图像到新图像的平均像素颜色是相同的。

https://github.com/danschumann/limby-resize

要包含的实际文件是

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

这将产生与 photoshop 或 imagemagick 相同类型的调整大小。

它有点慢,因为我们必须查看所有像素并重新分配每一点颜色,但对于不经常完成的工作,它可以工作。

算法背后的数学原理

假设我们将 3 个像素调整为 2 个像素。

通常,每个像素将有 4 个数字:红色、绿色、蓝色、alpha。让我们看一个简化版本,其中像素只是 1 个数字。

假设原始图像是:0 | 100 | 255

常规的画布 drawImage 调整大小将导致 0 | 100 或 0 | 255

这有时很好,但它会丢失细节,并且可能是一个非常丑陋和锯齿状的图像。如果你仔细想想,原来所有颜色的总和是 355(0 + 100 + 255),剩下平均像素 118.33。调整大小后的平均像素为 50 或 127.5,看起来还可以,也可能大不相同!

limby-resize 中实现的图像算法会产生与 imagemagick 相似的图像,保留所有像素数据,因此平均像素将相同。

我们的算法将生成以下图像:33 | 201.3

(0 * .66 + 100 * .33) | (100 * .33 + 255 * .66)

我们的总数是 234.3,剩下的平均值是 117.15,这将等于第一张图像(如果我们在此示例中不四舍五入到 2 位小数)。

浏览器支持

canvas_resize.js 应该能够包含在前端,以便更好地调整客户端大小。

var img, canvas, resized;
img = new Image;
img.onload = function(){
  canvas = document.createElement('canvas');
  canvas.width = img.width;
  canvas.height = img.height;
  canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height);
  resized = document.createElement('canvas');
  resized.width = 300;
  resized.height = 500;
  // see lib/canvas_resize for window.canvasResize = function(){...}
  canvasResize(canvas, resized);
  // resized will now be a properly resized version of canvas
}

img.src = '/path/to/img.jpg';

【讨论】:

  • @ThomasLeu 我知道它很慢。它只使用处理器——单线程。我想我可以编写一个 webgl 过滤器来并行执行相同的工作......可能会快几千倍......
猜你喜欢
  • 2021-02-15
  • 2011-05-09
  • 1970-01-01
  • 2010-10-22
  • 2012-03-20
  • 1970-01-01
  • 2017-04-29
  • 2011-01-19
相关资源
最近更新 更多