Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/395.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 在HTML5画布中调整图像大小_Javascript_Html_Canvas_Image Resizing - Fatal编程技术网

Javascript 在HTML5画布中调整图像大小

Javascript 在HTML5画布中调整图像大小,javascript,html,canvas,image-resizing,Javascript,Html,Canvas,Image Resizing,我试图使用javascript和canvas元素在客户端创建一个缩略图,但是当我缩小图像时,它看起来很糟糕。它看起来像是在photoshop中缩小的,重采样设置为“最近邻”,而不是双三次。我知道这是可能的,让它看起来正确,因为可以做得很好,使用画布以及。我试过使用“[Source]”链接中显示的代码,但看起来仍然很糟糕。是否有我遗漏的东西,需要设置的设置或其他什么 编辑: 我正在尝试调整jpg的大小。我曾尝试在链接站点和photoshop中调整同一个jpg的大小,缩小后看起来很好 以下是相关代码

我试图使用javascript和canvas元素在客户端创建一个缩略图,但是当我缩小图像时,它看起来很糟糕。它看起来像是在photoshop中缩小的,重采样设置为“最近邻”,而不是双三次。我知道这是可能的,让它看起来正确,因为可以做得很好,使用画布以及。我试过使用“[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:

画布:

具有图像渲染的图像:优化质量集并按宽度/高度缩放:

具有图像渲染的图像:优化质量集并使用-moz变换进行缩放:

在pixastic上调整画布大小:

我猜这意味着firefox并没有像预期的那样使用双三次采样。我只能等到他们真的加上去了

编辑3:


如果您只是想调整图像大小,我建议您使用CSS设置图像的
宽度
高度
。下面是一个简单的例子:

.small-image {
    width: 100px;
    height: 100px;
}
请注意,还可以使用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规则添加到图像选择器:

  • :介绍IE7
  • :FireFox 3.6中引入
据我所知,默认情况下,除了IE之外,所有浏览器都使用双三次算法来调整图像大小,所以在Firefox和Chrome中,调整大小的图像应该看起来不错

如果设置css
width
height
不起作用,您可能需要使用css
transform

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


有关更多详细信息,请参阅。

我通过右键单击firefox中的canvas元素并另存为获得了此图像

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

因此,我不久前在使用canvas时发现了一些有趣的东西,可能会有所帮助:

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

尝试将图像绘制到画布控件中,将“高度”和“宽度”属性设置为图像的大小,然后使用CSS将画布大小调整为所需的大小是值得的。也许这将使用不同的调整大小算法

还需要注意的是,画布在不同的浏览器(甚至不同版本的浏览器)中具有不同的效果。浏览器中使用的算法和技术可能会随着时间的推移而变化(特别是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";
};
现在是时候把你最好的浏览器放在那里,看看哪一个最不可能增加你客户的血压

嗯,我的讽刺标签在哪

(由于代码的许多部分都是基于GPL2的,所以它是否也包含在GPL2中?我不知道)


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

我强烈建议您检查并确保设置为true

控制图像缩放行为

Gecko 1.9.2(Firefox 3.6)中引入 /雷鸟3.1/Fennec 1.0)

Gecko 1.9.2介绍了 MozImageSmoothInEnabled属性到 canvas元素;如果此布尔值 值为false,图像将不会 缩放时平滑。此属性为 默认为true。是否查看纯打印

  • cx.mozImageSmoothingEnabled=假

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

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

    另外,很抱歉将jQuery用于简单的选择器,但我觉得语法太好了

    $(document).on('ready',createImage);
    $(窗口).on('resize',createImage);
    var createImage=函数(){
    var canvas=document.getElementById('myCanvas');
    canvas.width=window.innerWidth | |$(window.width();
    canvas.height=window.innerHeight | |$(window.height();
    var ctx=canvas.getContext('2d');
    img=新图像();
    img.addEventListener('load',functi
    
        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, .... )
    
    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();
    
    }
    
    $(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";
    }
    });
    
    /**
     * 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);
    }
    
    var img=document.createElement('img');
    img.src=canvas.toDataURL();
    $(img).css("background", backgroundColor);
    $(img).width(settings.width);
    $(img).height(settings.height);
    
      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] );
    
    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
        })
    })
    
    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);
    });