美文网首页
# sharp拼合头像

# sharp拼合头像

作者: nymlc | 来源:发表于2019-01-06 14:47 被阅读0次

前言

因为项目需要做个建群的时候取建群时群成员的头像拼合成一张图片作为群头像,所以用了这个库:sharp
实际操作一番,发现有些地方费劲,特此记录一下

直接上代码

const sharp = require('sharp');
const https = require('https');
const http = require('http');
/**
 * 读取本地
 * 
    const fs = require('fs');
    let dir = 'avatar/'
    let files = fs.readdirSync(dir);
    files = files.filter((item) => {
        const validExtRegex = /(?:bmp|gif|jpe?g|png)/
        return fs.statSync(dir + item).size != 0 && validExtRegex.test(item); // remove empty image
    }).map((item) => {
        return item = dir + item;
    })
 */
buildGetImageTasks = (urls) => {
    const tasks = []
    const buildTask = (url) => {
        return new Promise((resolve, reject) => {
            (url.startsWith('https') ? https : http).get(url, (res) => {
                const b = [];
                res.on('data', function (c) {
                    b.push(c);
                });
                res.on('end', function () {
                    resolve(Buffer.concat(b))
                });
                res.on('error', () => {
                    reject()
                });
            }).on('error', () => {
                reject()
            })
        })
    }
    if (!Array.isArray(urls)) {
        tasks.push(buildTask(urls))
    } else {
        urls.forEach(url => {
            tasks.push(buildTask(url))
        })
    }
    return tasks
}

compositeImage = (files, {
    size = 48,
    subSize = 12,
    padding = {
        top: 2,
        right: 2,
        bottom: 2,
        left: 2
    },
    margin = {
        top: 4,
        right: 4,
        bottom: 4,
        left: 4
    }
} = {}) => {
    // 创建底图层
    const base = sharp({
        create: {
            width: size,
            height: size,
            channels: 4,
            background: {
                r: 255,
                g: 255,
                b: 255,
                alpha: 128
            }
        }
    }).raw().toBuffer();
    // 拼合图片选项
    const options = {
        raw: {
            width: size,
            height: size,
            channels: 4
        }
    }
    // 计算多少行
    let columns = Math.ceil(Math.sqrt(files.length));
    // 最后一行差掉的间隙
    const hGap = (columns - (files.length % columns)) * (subSize + padding.left) / 2
    // 垂直差距
    const vGap = Math.ceil(files.length / columns) < columns ? (subSize + padding.top) / 2 : 0
    // 行列索引
    let x = 0;
    let y = 0;
    // 开始拼合
    const composite = files.reduce((input, overlay, index) => {
        return input.then(async (data) => {
            let temp = sharp(data, options).overlayWith(await sharp(overlay).rotate(180).resize(subSize, subSize).toBuffer(), {
                top: subSize * y + margin.top + padding.top * Math.floor(index / columns) + vGap,
                left: Math.floor(subSize * x + margin.left + padding.left * (index % columns) + (files.length % columns && (files.length - index) <= files.length % columns ? hGap : 0))
            }).raw().toBuffer();
            x += 1;
            if (x == columns) {
                x = 0;
                y += 1;
            }
            return temp;
        });
    }, base)
    return composite
}

bufferToFile = (composite, size, i) => {
    // 拼合结果转图片
    composite.then((data) => {
        sharp(data, {
            raw: {
                width: size,
                height: size,
                channels: 4
            }
        }).rotate(180)
            .toFile(`avatar/result${i}.jpg`, (err, output) => {
                console.log(output)
                if (err) {
                    console.log(err);
                }
            });
    });
}

for (let i = 3; i <= 9; i++) {
    const imgUrls = new Array(i).fill('http://img.downza.xzstatic.com/edu/pc/wlgj-1008/2016-07-26/c67d6f564bd270760be84cfb7d6fca3d.jpg')
    Promise.all(buildGetImageTasks(imgUrls)).then((res) => {
        let option = {
            size: 96,
            padding: {
                top: 4,
                right: 4,
                bottom: 4,
                left: 4
            },
            margin: {
                top: 8,
                right: 8,
                bottom: 8,
                left: 8
            }
        }
        switch (res.length) {
            case 3:
            case 4:
                Object.assign(option, {
                    subSize: 38
                })
                break
            default:
                Object.assign(option, {
                    subSize: 24
                })
        }
        bufferToFile(compositeImage(res, option), 96, i)
    })
}
  • 注意点1:网络取图不同于本地取图,它需要异步,可以使用Promise包裹nodejs的http、https模块取图。多张图的话可用Promise.all
  • 注意点2:sharp拼合图片很简单,就和PS图层操作一样,在一张底图之上把要拼合的图片按照以左上角为原点的笛卡尔坐标拼合,计算好每一张图片的偏移量就好了
  • 注意点3:像是微信群头像之类的以建群时头像来拼合(待拼合的头像数量不确定),可以将将读取到的图片buffer数组reserve,最后把拼合的图片rotate(180)即可

相关文章

  • # sharp拼合头像

    前言 因为项目需要做个建群的时候取建群时群成员的头像拼合成一张图片作为群头像,所以用了这个库:sharp。实际操作...

  • websocket-sharp使用手册

    Welcome to websocket-sharp! websocket-sharp supports: RFC...

  • The Weekly Test

    sharp:at two o'clock sharp 两点整 utter:complete – used espe...

  • 拼合沙发

    拼合沙发

  • 拼合沙发

    拼合沙发

  • to be sharp

    in a system。 个体生存的不二法则。

  • 2018-04-02

    C Sharp图解教程

  • js 数组拼合

    数组的拼合 1.concat 但是要引入新的变量来承接两个数组的拼合的结果,会导致虚耗内存 2.使用for循环加p...

  • 信息化

    1,2016年,sharp, ipguard

  • 图片精灵

    div css sprites精灵-CSS图像拼合 CSS贴图定位网页背景素材图片拼合定位布局技术教程篇与css ...

网友评论

      本文标题:# sharp拼合头像

      本文链接:https://www.haomeiwen.com/subject/oyssrqtx.html