pixi.js实现lut颜色映射滤镜实例页面

回到相关文章 »

效果:

原始图片

原始图

处理图片

代码:

HTML代码:
<h4>原始图片</h4>
<p>
    <img src="./example.jpg" alt="原始图">
</p>
<h4>处理图片</h4>
<canvas width="600" height="258"></canvas>
JS代码:
<script src="./pixi.js"></script>
<script type="module">
    import { ColorMapFilter } from 'https://cdn.jsdelivr.net/npm/@pixi/filter-color-map@5.1.1/+esm'

    const imgUrl = './example.jpg';
    const cubeUrl = './Candlelight.cube';

    // canvas 元素与转换成PIXI的view
    const canvas = document.querySelector('canvas');
    const view = canvas.transferControlToOffscreen();

    const app = new PIXI.Application({
        view,
        width: 600,
        height: 258,
        resolution: 1
    });

    // 加载图片
    const imgContainer = new PIXI.Container();
    app.stage.addChild(imgContainer);

    // 图片精灵
    const imgSprite = PIXI.Sprite.from(imgUrl);
    imgSprite.width = 600;
    imgSprite.height = 258;
    imgContainer.addChild(imgSprite);

    // 加载cube文件为文本格式
    fetch(cubeUrl).then(res => res.text()).then(text => {
        const lut = parseCubeLUT(text);
        const lutImage = lut2Img(lut);
        const colorMapFilter = new ColorMapFilter(lutImage); 
        imgContainer.filters = [colorMapFilter];
    });

    // 解析cube文件的方法
    const parseCubeLUT = function (str) {
        if (typeof str !== 'string') {
            str = str.toString();
        }

        var title = null;
        var type = null;
        var size = 0;
        var domain = [[0.0, 0.0, 0.0], [1.0, 1.0, 1.0]];
        var data = [];

        var lines = str.split('\n');

        for (var i=0; i<lines.length; i++) {
            var line = lines[i].trim();

            if(line[0] === '#' || line === '') {
                // Skip comments and empty lines
                continue;
            }

            var parts = line.split(/\s+/);

            switch(parts[0]) {
                case 'TITLE':
                    title = line.slice(7, -1);
                    break;
                case 'DOMAIN_MIN':
                    domain[0] = parts.slice(1).map(Number);
                    break;
                case 'DOMAIN_MAX':
                    domain[1] = parts.slice(1).map(Number);
                    break;
                case 'LUT_1D_SIZE':
                    type = '1D';
                    size = Number(parts[1]);
                    break;
                case 'LUT_3D_SIZE':
                    type = '3D';
                    size = Number(parts[1]);
                    break;
                default:
                    data.push(parts.map(Number));
            }
        }

        return {
            title: title,
            type: type,
            size: size,
            domain: domain,
            data: data
        };
    }

    // cube data 转PNG图片的实现
    const lut2Img = function (lutData) {
        const { size, data } = lutData;

        // 根据size创建canvas元素
        const canvas = document.createElement('canvas');
        canvas.width = size * size;
        canvas.height = size;

        // 绘制在Canvas上
        const context = canvas.getContext('2d');
        const imagedata = context.createImageData(canvas.width, canvas.height);
        // 给对应坐标位置的数据设置色值为绿色
        let startX = 0;
        let startY = 0;
        for (var x = 0; x < data.length; x++) {
            // var index = 4 * x;
            // 垂直计算位置
            startY = Math.floor(x / size) % size;
            startX = x % size + size * Math.floor(Math.floor(x / size) / size);

            // index 计算
            var index = 4 * (startY * size * size + startX);

            imagedata.data[index] = data[x][0] * 255;
            imagedata.data[index + 1] = data[x][1] * 255;
            imagedata.data[index + 2] = data[x][2] * 255;
            imagedata.data[index + 3] = 255;
        }
        // 再重绘
        context.putImageData(imagedata, 0, 0);

        return canvas;
    };
</script>