【问题标题】:Apply and save image effects on Canvas javascript在 Canvas javascript 上应用和保存图像效果
【发布时间】:2016-07-05 06:43:58
【问题描述】:

我必须实现具有灰度、模糊等效果的图像过滤器。 我有 dataURL 格式的图像。有人可以指导我在不丢失图像大小的情况下实现它吗?

如果我将图像添加到画布进行操作,它会缩放到画布框大小。也无法在画布/图像上应用 css 过滤器并保存它。当我保存时,它有原始图像

【问题讨论】:

    标签: css image canvas css-filters


    【解决方案1】:

    使用画布应用过滤器

    过滤属性

    虽然 chrome 和 firefox 都支持 ctx.filter 属性,但它们需要设置浏览器标志才能激活。激活后,2d 上下文的过滤器属性将使用 CSS 过滤器语法并将过滤器应用于所有渲染调用。参考MDN CanvasRenderingContext2D.filter

    ctx.filter = "blur(5px)";  // only applies to proceeding rendering calls existing
                               // current pixels remain unchanged
    ctx.drawImage(image,0,0);  // draw an image blurred 5px
    

    对图像应用滤镜。 适用于设置了相应浏览器标志的 Chrome 和 FIrefox。

    // assume image is a loaded image
    var filteredImage = document.createElement("canvas");
    var ctx = filteredImage.getContext('2d');
    filteredImage.width = image.width;
    filteredImage.height = image.height;
    ctx.filter = "blur(10px) grayscale(100%)";
    ctx.drawImage(image, 0, 0); // draw the image applying the filter
    ctx.filter = ""; // turn off the filter as no needed any more
    
    // You can now save the image filteredImage by using
    ctx.toDataURL("image/jpeg",0.75); 
    

    最简单的解决方案

    如果您需要完整的浏览器支持,则必须找到一个 Javascript 过滤器库,有很多可供选择,尽管我不会认可其中任何一个。

    自己写

    另一种方法是编写自己的过滤器,(一个很好的学习机会)大多数过滤器都是非常简单的像素操作函数,并且有很多关于各种过滤器如何工作的信息。要了解有关 2D API 的更多信息MDN CanvasRenderingContext2D 和卷积滤波器的快速入门Image Filters with Canvas

    例如一个灰度过滤器(最基本的卷积过滤器将红绿蓝通道的加权和转换为灰度)

    const PERS_R = 0.2;  // approx human perceptual frequency / intensity response for r,g,b popular in the CG world and based on Manhattan 0.2126, 0.7152, 0.0722
    const PERS_G = 0.7;  // for red green and blue
    const PERS_B = 0.1; 
    function applyGreyScale(image, percent, perc){ // 0 < percent >= 100
        if(image === null || image === undefined){
            throw new ReferenceError("applyGreyScale argument image is undefined or null");
        }
        const p = percent === undefined ? 1: percent / 100;
        const rp = 1-p; // reciprocal of p
        perc = 1 - (perc === undefined ? 0 : Math.min(1, Math.max(0,perc))); // clamp if defined
        var filteredImage = document.createElement("canvas");
        var ctx = filteredImage.getContext('2d');
        const w = filteredImage.width = image.width;
        const h = filteredImage.height = image.height;
        ctx.drawImage(image, 0, 0); // draw the image
        var imageData = ctx.getImageData(0, 0, w ,h); // get the pixel data
        var dat = imageData.data; // reference the pixel data
        var ind = (w * h * 4) - 4; // pixel data array index point to last pixel each pixel is 4 bytes RGBA
        const mean = 1/3; // mean contribution of each channel to gray
        const pr = PERS_R + perc * (mean - PERS_R);
        const pg = PERS_G - perc * (PERS_G- mean);
        const pb = PERS_B + perc * (mean - PERS_B);
        var grey; 
        while(ind >= 0){  // do for all pixels
            grey = dat[ind] * pr;      // get gray by adding each channel's contribution
            grey += dat[ind + 1] * pg; 
            grey += dat[ind + 2] * pb;
            dat[ind] = rp * dat[ind] + p * grey; // mix the grey with the existing colour
            dat[ind + 1] = rp * dat[ind + 1] + p * grey; // mix the grey with the existing colour        
            dat[ind + 2] = rp * dat[ind + 2] + p * grey; // mix the grey with the existing colour
            ind -= 4;
        }
        ctx.putImageData(imageData,0,0); // put the new pixels back on the image
        filteredImage.ctx = ctx; // Add 2D context for later use
        return filteredImage; // return the filtered image
    }
    
    /*
    To use applyGreyScale(image [, percent [, perc]]) where percent and perc are optional
    image is the image to get a gray scale from
    percent is the amount of gray to apply 0 is none 100 is full. Default 100
    perc is the amount of the perception curve applied to the grey. 0 no perception adjustment, 1 is full perceptual adjustment. Default is 1
    Returns image with ctx property added for access to 2D interface
    */
    

    而且比较好用

    // convert image to greyscaled image
    var dataURL = applyGreyScale(image).ctx.toDataURL("image/jpeg",0.75);
    

    【讨论】:

    • ctx.filter 适用于所有浏览器,除了 MS 系列(Edge 和 IE)。
    【解决方案2】:

    将图像添加到另一个图像的源:

    var canvas = document.getElementById('id');
    var ctx = myCanvas.getContext('2d');
    var img = new Image();
    img.onload = function(){
        canvas.width = img.width;
        canvas.height = img.height;
        //The 4th, and 5th parameters set the image at it's own dimensions.
        //The 2nd, and 3rd parameters set the image at the upper left of the canvas.
        ctx.drawImage(img, 0, 0, img.width, img.height);
        //Your image manipulation code here.
    };
    img.src = dataurlString;
    

    这将使画布与图像一样大,但我假设您希望保留分辨率。

    您还需要将所有操作放在 onload 侦听器中。

    【讨论】:

    • 您好,感谢您的回复。我正在尝试使用过滤器 imageData.style["filter"] = "grayValue(0.5)" / ctx.style["filte"]="grayValue(0.5)" 进行操作,但代码似乎不起作用。有相同的输入吗?
    • 您不能在样式上使用filter。你必须直接使用它ctx.filter。请参阅@Blindman67 的回答。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-22
    • 2021-08-01
    • 1970-01-01
    相关资源
    最近更新 更多