Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/434.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用javascript画布调整图像大小(平滑)_Javascript_Html_Image_Canvas_Html5 Canvas - Fatal编程技术网

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

使用javascript画布调整图像大小(平滑),javascript,html,image,canvas,html5-canvas,Javascript,Html,Image,Canvas,Html5 Canvas,我试图用画布调整一些图像的大小,但我不知道如何平滑它们。 在photoshop、浏览器等上。。他们使用了一些算法(例如双三次、双线性),但我不知道这些算法是否内置在画布中 这是我的小提琴: 第一个是正常大小的图像标记,第二个是画布。请注意画布是如何变得不那么平滑的。如何实现“平滑度”?您可以使用下一步来获得更好的效果。大多数浏览器在调整图像大小时都会显示错误 (更新规范中添加了一个质量属性,该属性目前仅在Chrome中可用。) 除非选择“无平滑”或“最近邻”,否则浏览器将始终在向下缩放图像后对其

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

这是我的小提琴:


第一个是正常大小的图像标记,第二个是画布。请注意画布是如何变得不那么平滑的。如何实现“平滑度”?

您可以使用下一步来获得更好的效果。大多数浏览器在调整图像大小时都会显示错误

更新规范中添加了一个质量属性,该属性目前仅在Chrome中可用。)

除非选择“无平滑”或“最近邻”,否则浏览器将始终在向下缩放图像后对其进行插值,因为此函数用作低通滤波器以避免锯齿

双线性使用2x2像素进行插值,而双立方使用4x4像素,因此通过分步进行插值,您可以在使用双线性插值时获得接近双立方的结果,如结果图像中所示

var canvas=document.getElementById(“canvas”);
var ctx=canvas.getContext(“2d”);
var img=新图像();
img.onload=函数(){
//设置与图像成比例的大小
canvas.height=canvas.width*(img.height/img.width);
//步骤1-调整大小至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.宽度,oc.高度);
//步骤2
octx.drawImage(oc,0,0,oc.宽度*0.5,oc.高度*0.5);
//步骤3,调整大小至最终大小
ctx.drawImage(oc,0,0,oc.宽度*0.5,oc.高度*0.5,
0,0,canvas.width,canvas.height);
}
img.src=“//i.imgur.com/SHo6Fub.jpg”

我创建了一个库,允许您在保留所有颜色数据的同时降低任何百分比


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

我创建了一个可重用的角度服务,为感兴趣的任何人处理高质量的图像/画布大小调整:

该服务包括两种解决方案,因为它们都有各自的优缺点。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
    })
})

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

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);
更新JSFIDLE演示版

这是我的

因为根本不正确 (它只使用最后一步中的原始图像)
我自己写了一篇关于性能比较的文章:

基本上是:

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

我编写了一个小js实用程序来裁剪和调整前端图像的大小。下面是关于GitHub项目的介绍。您还可以从最终图像中获取blob来发送它

import imageSqResizer from './image-square-resizer.js'

let resizer = new imageSqResizer(
    'image-input',
    300,
    (dataUrl) => 
        document.getElementById('image-output').src = dataUrl;
);
//Get blob
let formData = new FormData();
formData.append('files[0]', resizer.blob);

//get dataUrl
document.getElementById('image-output').src = resizer.dataUrl;

虽然其中一些代码片段很短而且有效,但要理解它们并不是一件小事

由于我不喜欢stack overflow中的“复制粘贴”,我希望开发人员能够理解他们在软件中使用的代码,希望您会发现下面的内容很有用

演示:使用JS和HTML画布演示提琴器调整图像大小

您可能会发现3种不同的方法来调整大小,这将帮助您了解代码是如何工作的以及为什么

您可能希望在代码中使用的demo和TypeScript方法的完整代码可以在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
        }
    };
}}
导出类ImageTools{
base64ResizedImage:string=null;
构造函数(){
}
调整图像大小(Base64图像:字符串,宽度:数字=1080,高度:数字=1080){
设img=新图像();
img.src=base64image;
img.onload=()=>{
//检查图像是否需要调整大小
如果(如高度和宽度){
//将调整大小的画布缩小一半并刷新图像
halfImageDimensions.width=数学地板(curImageDimensions.width*0.5);
halfImageDimensions.height=数学地板(curImageDimensions.height*0.5);
resizingCanvasContext.drawImage(resizingCanvas,0,0,curImageDimensions.width,curImageDimensions.height,
0,0,halfImageDimensions.width,halfImageDimensions.height);
curImageDimensions.width=半图像Dimensions.width;
curImageDimensions.height=半图像Dimensions.height;
}
//现在对调整尺寸的Canvas进行最终调整,以满足尺寸要求
//直接输出到输出画布,将输出最终图像
让outputCanvas:htmlcanvaseElement=document.createElement('canvas');
让outputCanvasContext=outputCanvas.getContext(“2d”);
outputCanvas.width=宽度;
outputCanvas.height=高度;
outputCanvasContext.drawImage(大小调整Canvas,0,0,curImageDimensions.width,curImageDimensions.height,
0,0,宽度,高度);
//将画布像素输出为图像。参数:格式、质量
this.base64ResizedImage=outputCanvas.toDataURL('image/jpeg',0.85);
//TODO:调用方法对调整图像大小进行处理
}
};
}}

我不明白为什么没有人建议
createImageBitmap

createImageBitmap(
    document.getElementById('image'), 
    { resizeWidth: 300, resizeHeight: 234, resizeQuality: 'high' }
)
.then(imageBitmap => 
    document.getElementById('canvas').getContext('2d').drawImage(imageBitmap, 0, 0)
);

工作得很好(假设你为图像和画布设置了ID)。

@steve heh,有时会发生以下情况:)对于图像,你通常可以通过设置css来覆盖这一点。Ken,第一个结果非常有效,但当我更改图像时,你会发现它太模糊了,在这种情况下和其他情况下可以做什么?@steve你可以减少数量
createImageBitmap(
    document.getElementById('image'), 
    { resizeWidth: 300, resizeHeight: 234, resizeQuality: 'high' }
)
.then(imageBitmap => 
    document.getElementById('canvas').getContext('2d').drawImage(imageBitmap, 0, 0)
);