webp 前端使用wasm转换图片格式

webp 前端使用wasm转换图片格式

node库

https://github.com/scionoftech/webp-converter#readme

可能会需要设置权限

sudo chmod a+x  /Users/ace/Documents/code/demo/test-demo/node_modules/webp-converter/bin/libwebp_osx/bin/cwebp

 

使用 

const webp = require("webp-converter");

 
const imgPath = "./s2.jpg"
const jsOutPath = ["./js-out", +new Date(), ".wepb"].join("")
const result = webp.cwebp(imgPath, jsOutPath, "-q 80");
result.then((response) => {
    console.log(response);
});

 

直接引入即可

https://webpjs.appspot.com/

或者使用挂载脚本

(function () {
    var WebP = new Image();
    WebP.onload = WebP.onerror = function () {
        if (WebP.height != 2) {
            var sc = document.createElement("script");
            sc.type = "text/javascript";
            sc.async = true;
            var s = document.getElementsByTagName("script")[0];
            sc.src = "js/webpjs-0.0.2.min.js";
            s.parentNode.insertBefore(sc, s);
        }
    };
    WebP.src = "data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA";
})();

 

 

 

编译自己的webp库

clone 仓库

https://github.com/webmproject/libwebp

 

在目录同级新建webp.c, 编译库

#include "emscripten.h"
#include "src/webp/encode.h"
#include <stdlib.h>

int result[2];

EMSCRIPTEN_KEEPALIVE
int version()
{
    return WebPGetEncoderVersion();
}

EMSCRIPTEN_KEEPALIVE
uint8_t *create_buffer(int width, int height)
{
    return malloc(width * height * 4 * sizeof(uint8_t));
}

EMSCRIPTEN_KEEPALIVE
void destroy_buffer(uint8_t *p)
{
    free(p);
}

EMSCRIPTEN_KEEPALIVE
void encode(uint8_t *img_in, int width, int height, float quality)
{
    uint8_t *img_out;
    size_t size;
    size = WebPEncodeRGBA(img_in, width, height, width * 4, quality, &img_out);
    result[0] = (int)img_out;
    result[1] = size;
}

EMSCRIPTEN_KEEPALIVE
void free_result(uint8_t *result)
{
    WebPFree(result);
}

EMSCRIPTEN_KEEPALIVE
int get_result_pointer()
{
    return result[0];
}

EMSCRIPTEN_KEEPALIVE
int get_result_size()
{
    return result[1];
}
/*
允许动态增加内存, 不然会OOM

emcc -O3 -s WASM=1 -s EXTRA_EXPORTED_RUNTIME_METHODS="["cwrap"]" 
    -I libwebp 
    webp.c 
    -s ALLOW_MEMORY_GROWTH 
    libwebp/src/{dec,dsp,demux,enc,mux,utils}/*.c
*/

得到产物

 

node的使用方式, 需要借助库image-pixels获取imageData

const Module = require("./a.out")
const fs = require("fs")
var pixels = require("image-pixels")
const webp = require("webp-converter");

// 图片太大会OOM
// const imgPath = "./s.jpg"
const imgPath = "./s3.jpg"
const wasmOutPath = "./wasm-out.webp"

async function getImageData() {
    return pixels(imgPath)
}

Module.onRuntimeInitialized = async () => {
    const api = {
        version: Module.cwrap("version", "number", []),
        create_buffer: Module.cwrap("create_buffer", "number", ["number", "number"]),
        destroy_buffer: Module.cwrap("destroy_buffer", "", ["number"]),
        encode: Module.cwrap("encode", "", ["number", "number", "number", "number"]),
        free_result: Module.cwrap("free_result", "", ["number"]),
        get_result_pointer: Module.cwrap("get_result_pointer", "number", []),
        get_result_size: Module.cwrap("get_result_size", "number", []),
    };
    console.log(api.version());
    const {data, width, height} = await getImageData()
    const q = 75

    const st1 = +new Date()
    const p = api.create_buffer(width, height);
    Module.HEAP8.set(data, p);
    api.encode(p, width, height, q);
    console.log("time1:", +new Date() - st1)
    const resultPointer = api.get_result_pointer();
    const resultSize = api.get_result_size();
    console.log("time12:", +new Date() - st1)
    console.log(resultPointer, resultSize)
    const resultView = new Uint8Array(Module.HEAP8.buffer, resultPointer, resultSize);
    const result = new Uint8Array(resultView);
    console.log("time123:", +new Date() - st1)
    console.log(result.length / 1024)
    // console.log("time1:", +new Date() - st1)
    // const blob = new Blob([result], {type: "image/webp"});
    api.destroy_buffer(p);


    const jsOutPath = "./js-out" + (+new Date()) + ".webp"
    const st2 = +new Date()
    const result2 = await webp.cwebp(imgPath, jsOutPath, `-q ${q}`);
    console.log("time2:", +new Date() - st2)
}

 

 

web的使用方式

// const Module = require("./a.out")
// const fs = require("fs")

// 图片太大会OOM
const imgPath = "./t.jpg"
const wasmOutPath = "./wasm-out.webp"

Module.onRuntimeInitialized = async () => {
    const api = {
        version: Module.cwrap("version", "number", []),
        create_buffer: Module.cwrap("create_buffer", "number", ["number", "number"]),
        destroy_buffer: Module.cwrap("destroy_buffer", "", ["number"]),
        encode: Module.cwrap("encode", "", ["number", "number", "number", "number"]),
        free_result: Module.cwrap("free_result", "", ["number"]),
        get_result_pointer: Module.cwrap("get_result_pointer", "number", []),
        get_result_size: Module.cwrap("get_result_size", "number", []),
    };
    console.log(api.version());
    // const buffer = fs.readFileSync(imgPath)

    const imgBlob = await fetch(imgPath).then(resp => resp.blob());
    const blobURL = URL.createObjectURL(imgBlob);
    const img = document.createElement("img")
    img.src = blobURL
    document.body.appendChild(img);

    // const blobURL = URL.createObjectURL(buffer);
    // const img = document.createElement("img")
    // img.src = imgPath
    img.onload = () => {
        console.log("===", "onload");
        const canvas = document.createElement("canvas");
        canvas.width = img.width;
        canvas.height = img.height;
        document.body.appendChild(canvas);
        const ctx = canvas.getContext("2d");
        ctx.drawImage(img, 0, 0);
        const data = ctx.getImageData(0, 0, img.width, img.height)
        console.log("data", data,img.width,data.width)

        const p = api.create_buffer(data.width, data.height);
        Module.HEAP8.set(data.data, p);
        api.encode(p, data.width, data.height, 75);
        const resultPointer = api.get_result_pointer();
        const resultSize = api.get_result_size();
        console.log(resultPointer, resultSize)


        const resultView = new Uint8Array(Module.HEAP8.buffer, resultPointer, resultSize);
        const result = new Uint8Array(resultView);
        const blob = new Blob([result], {type: "image/webp"});
        const blobURL = URL.createObjectURL(blob);
        const img2 = document.createElement("img");
        img2.src = blobURL;
        document.body.appendChild(img2);

        api.destroy_buffer(p);


        const WebP = new Image();
        WebP.onload = WebP.onerror = function () {
            if (WebP.height !== 2) {
                const sc = document.createElement("script");
                sc.type = "text/javascript";
                sc.async = true;
                const s = document.getElementsByTagName("script")[0];
                sc.src = "js/webpjs-0.0.2.min.js";
                s.parentNode.insertBefore(sc, s);
            }
        };
        WebP.src = imgPath
}
// console.log(blobURL)
/*    async function loadImage(imgBlob) {
        // const imgBlob = await fetch(src).then(resp => resp.blob());
        const img = await createImageBitmap(imgBlob);
        const canvas = document.createElement("canvas");
        canvas.width = img.width;
        canvas.height = img.height;

        document.body.appendChild(canvas);

        const ctx = canvas.getContext("2d");
        ctx.drawImage(img, 0, 0);
        return {
            width: img.width,
            height: img.height,
            data: ctx.getImageData(0, 0, img.width, img.height)
        }
    }
    const imageInfo = await loadImage(imageBlob);
    const p = api.create_buffer(imageInfo.width, imageInfo.height);
    Module.HEAP8.set(imageInfo.data.data, p);
    api.encode(p, imageInfo.width, imageInfo.height, 75);
    const resultPointer = api.get_result_pointer();
    const resultSize = api.get_result_size();
    api.destroy_buffer(p);*/

}

html文件中引入

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="js/webpjs-0.0.2.min.js"></script>
    <script src="a.out.js"></script>
    <script src="./wasm.js"></script>
</head>
<body>

</body>
</html>

 

hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » webp 前端使用wasm转换图片格式