为什么我不能在画布上恢复光度?

时间:2014-07-14 09:02:45

标签: javascript canvas

我使用画布来设置图像的亮度。如果我只设置亮度一次,这项工作正常。但是如果我将亮度重置为0,我就不会得到默认图像。我不知道为什么。

调用效果的代码:

var mainEffect = new CanvasEffect(canvas[0]);
var thumbsEffect = new CanvasEffect(thumbs[0]);
luminositySlider.change(function() {
    var intensity = luminositySlider.val();
    mainEffect.apply("luminosity", intensity);
    thumbsEffect.apply("luminosity", intensity);
});

这是我使用的代码,int是从html滑块获得的。之前的亮度存储在一个数组中:

function CanvasEffect(canvas) {
var ctx = canvas.getContext("2d");
var WIDTH = canvas.width;
var HEIGHT = canvas.height;
var stack = [];
var imageData;
var data;

this.apply = function(effect, intensity) {
    imageData = ctx.getImageData(0,0, WIDTH, HEIGHT);
    data = imageData.data;
    var int = Number(intensity);
    var refresh =  true;
    switch (effect) {
    case "blur":
        refresh = false;
        stackBlurCanvasRGB('canvas', 0, 0,  WIDTH, HEIGHT, int);
        break;
    case "sharpen":

        break;
    case "luminosity":
        console.log("stack['luminosity'] : " + stack["luminosity"]);
        lastInt = (stack["luminosity"] == undefined) ? 0 : stack["luminosity"];
        newInt = int - lastInt;
        console.log("int : " + int, "lastInt : " + lastInt, "newInt : " + newInt);
        for(var i=0;i < data.length;i+=4) {
            data[i] += newInt; //Red
            data[i+1] += newInt; //Green
            data[i+2] += newInt; //Blue
        }
        break;
    case "contrast":
        lastInt = (stack["contrast"] == undefined) ? 0 : stack["contrast"];
        newInt = int - lastInt;
        var factor = (259 * (newInt + 255)) / (255 * (259 - newInt));
        for(var i = 0; i < data.length ; i+=4) {
            data[i] = factor *  (data[i] - 128) + 128; //Red
            data[i+1] = factor *  (data[i+1] - 128) + 128; //Green
            data[i+2] = factor *  (data[i+2] - 128) + 128; //Blue
        }
        break;
    case "negatif":
        console.log("negatif");
        for(var i=0;i < data.length;i+=4) {
            data[i] = 256-data[i]; //Red
            data[i+1] = 256-data[i+1]; //Green
            data[i+2] = 256 - data[i+2]; //Blue
        }
        break;
    case "b&w":
        console.log("b&w");
        for(var i=0;i < data.length;i+=4) {
            var gris = data[i]*0.3 + data[i+1]*0.59 + data[i+2]*0.11;
            data[i] = gris; //Red
            data[i+1] = gris; //Green
            data[i+2] = gris; //Blue
        }
        break;
    case "sepia":
        console.log("sepia");
        for(var i=0;i < data.length;i+=4) {
            var r = data[i]*0.299 + data[i+1]*0.587 + data[i+2]*0.114;
            data[i] = Math.max(0, Math.min(255, r*1.351)); //Red
            data[i+1] = Math.max(0, Math.min(255, r*1.203)); //Green
            data[i+2] = Math.max(0, Math.min(255, r*0.937)); //Blue
        }
        break;
    default:
        break;
    }

    if(refresh) {
        imageData.data = data;
        ctx.putImageData(imageData,0 ,0);
    }
    // Stores the effect to recalculate if it changes
    stack[effect] = int;
};

}

原始图片:

Original Image

最高光度的图像:

Image with luminosity to 100

将图像重置为原始图像(亮度0):

Reset image to the original

2 个答案:

答案 0 :(得分:2)

r,g,b,如你所知,一个组件存储在8位上,这个位太少而不能进行多次操作:在每次操作时,都会发生舍入和钳位。

解决方案是使用Float32Array存储图像的组件。然后你可以进行任何种类和数量的操作(几乎)没有质量损失。

答案 1 :(得分:1)

刻录了图片losing information。您需要从文件重新加载图像以恢复过度曝光像素的信息。

一旦画布加载图像,它就会“忘记”原始文件,只处理加载的像素。当你增加亮度时,该图片的一个大区域会丢失信息,因为它“超出规模”。除非再次重新加载图片,否则无法恢复丢失的信息。

更新:正如@GameAlchemist建议的那样,您可以创建自己的数组:

var image= new Int32Array(originalByteArray); //Or Float32Array, I'd test both

并在那里存储图像的副本。然后,对该数组进行所有操作并复制图像数据中的输出,只占用前8位。