纯前端实现视频添加水印效果实例页面

回到相关文章 »

效果:

视频资源

水印图片

代码:

JS代码:
// 顶层变量存储文件对象,供后续合成使用
let videoFile = null;
let imageFile = null;

// 视频选择与预览
fileVideo.addEventListener('change', (event) => {
    const file = event.target.files[0];
    if (file) {
        videoFile = file;
        const url = URL.createObjectURL(file);
        videoPreview.innerHTML = `<video src="${url}" controls></video>`;
    }
});

// 图片选择与预览
fileImage.addEventListener('change', (event) => {
    const file = event.target.files[0];
    if (file) {
        imageFile = file;
        const url = URL.createObjectURL(file);
        imagePreview.innerHTML = `<img src="${url}">`;
    }
});

const {
    Input,
    Output,
    Conversion,
    ALL_FORMATS,
    BlobSource,
    Mp4OutputFormat,
    BufferTarget
} = Mediabunny;


form.addEventListener('submit', async (event) => {
    event.preventDefault();

    const submit = form.querySelector('button');
    submit.textContent = '合成中...';   
    submit.disabled = true;
    
    // 水印图片
    const watermark = imagePreview.querySelector('img');

    const input = new Input({
        formats: ALL_FORMATS,
        source: new BlobSource(videoFile)
    });
    const output = new Output({
        format: new Mp4OutputFormat(), // The format of the file
        target: new BufferTarget()
    });

    let ctx = null;
    const conversion = await Conversion.init({
        input,
        output,
        video: {
            process: (sample) => {
                if (!ctx) {
                    // Create a canvas for image compositing
                    const canvas = new OffscreenCanvas(
                        sample.displayWidth,
                        sample.displayHeight
                    );
                    ctx = canvas.getContext('2d');
                }

                ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
                sample.draw(ctx, 0, 0);
                ctx.drawImage(watermark, 80, 80 * watermark.naturalHeight / watermark.naturalWidth);

                return ctx.canvas;
            }
        }
    });

    conversion.onProgress = function (progress) {
        submit.textContent = `合成中...${Math.round(progress * 100)}%`;
    };

    await conversion.execute();

    const buffer = output.target.buffer;
    const url = URL.createObjectURL(new Blob([buffer]));
    result.innerHTML = `<video src="${url}" controls></video>`;
    submit.textContent = '开始合成';   
    submit.disabled = false;
});