Introduction to WebAssembly: How to integrate with C/C++ projects
What is WebAssembly?
- A new type of code that runs in a Web browser, provides some new features and focuses primarily on high performance
- Not primarily for writing, but for C/C++, C#, Rust, etc., so you can take advantage of it even if you don’t know how to write WebAssembly code
- Code written in other languages can run at close to native speed, and client apps can run on the Web
- WebAssembly modules can be imported into a browser or Node.js, and JS frameworks can use WebAssembly to gain huge performance advantages and new features while being functionally easy to use
The goal of WebAssembly
- Fast, efficient, and convenient – cross-platform execution at near-native speed by leveraging some common hardware capabilities
- Readable, debuggable – WebAssembly is a low-level assembly language, but it also has a human-readable text format that makes it possible to write code, view code, and debug code.
- Secure – WebAssembly explicitly runs in a secure, sandbox execution environment, similar to other Web code, which enforces same-origin and some permission policies.
- Don’t break existing Web – WebAssembly is designed to run compatible with other Web technologies and maintain backward compatibility.
How is WebAssembly compatible with the Web?
The Web platform can be viewed as having two parts:
- A virtual machine (VM) is used to run Web application code, such as a JS engine that runs JS code
- A series of Web apis that Web applications can call to control the functionality of Web browsers/devices to do certain things (DOM, CSSOM, WebGL, IndexedDB, Web Audio API, etc.)
For a long time, a VM could only load JS to run, and JS might be enough for our needs, but now we have all kinds of performance issues such as 3D games, VR/AR, computer vision, image/video editing, and other areas that require native performance.
At the same time, it is very difficult to download, parse and compile large JS applications, and this performance bottleneck will be more severe on some more resource-constrained platforms, such as mobile devices.
WebAssembly is a different language from JavaScript. It is not designed to replace JS, but is designed to complement and collaborate with JS, enabling Web developers to reuse the best of both languages:
- JS is a high-level language that is flexible and expressive, dynamically typed, does not require compilation steps, and has a powerful ecology that makes it easy to write Web applications.
- WebAssembly is a low-level, assembly-like language that uses a compact second-level format, runs at near-native performance, and provides a low-level memory model. It is the target of compilation for languages such as C++ and Rust to enable code written in such languages to run on the Web (note that, WebAssembly will provide high-level goals such as an in-memory model for garbage collection in the future)
With the advent of WebAssembly, the VM mentioned above can now load two types of code execution: JavaScript and WebAssembly.
JavaScript and WebAssembly can interoperate. In fact, a piece of WebAssembly code is called a module, and WebAssembly modules have many features in common with ES2015 modules.
Key concepts of WebAssembly
To understand how WebAssembly works on the Web, you need to understand a few key concepts:
- Module: WebAssembly binaries compiled into executable machine code by the browser. Module is stateless, like a Blob, and can pass between Windows and workers
postMessage
Shared, a Module that declares import and export similar to ES2015 modules. - Memory: A resizable ArrayBuffer that contains linear arrays of bytes read and written by WebAssembly’s low-level Memory access instructions.
- Table: A resizable array of typed references (such as functions) that, for security and portability reasons, cannot be stored in memory as raw bytes
- Instance: A Module that contains all the states it uses at runtime, including Memory, Table, and a set of imported values. An Instance, like an ES2015 Module, is loaded into a specific global variable with a specific set of imports
WebAssembly’s JavaScript API provides developers with the ability to create Modules, Memory, tables, and instances. Given a WebAssembly Instance, JS code can call its exports synchronously — exported as normal JavaScript functions. Any JavaScript function can be called synchronously by WebAssembly code by passing JavaScript functions as imports to WebAssembly Instance.
Because JavaScript has complete control over how WebAssembly code is downloaded, compiled, and run, JavaScript developers can assume that WebAssembly is just a new feature of JavaScript — the ability to efficiently generate high-performance functions.
In the future, WebAssembly modules can be loaded as ES2015 module loads, such as
How to use WebAssembly in an application?
WebAssembly adds two things to the Web platform: a binary format code and a set of apis for loading and executing binaries.
WebAssembly is at an embryonic point, and there are sure to be a lot of tools coming, but there are four main entry points:
- Use EMScripten to port C/C++ applications
- Write and generate WebAssembly code directly at the assembly level
- Write the Rust application and use WebAssembly as its output
- Use AssemblyScript, a typescript-like language that compiles to WebAssembly binaries
Porting C/C++ applications
Although there are some other tools such as:
- WasmFiddle
- WasmFiddle++
- WasmExplorer
However, all of these tools lack EMScripten’s tool chain and optimization operations. The specific operation process of EMScripten is as follows:
- EMScripten feeds the C/C++ code to the Clang compiler, a C/C++ compiler based on the LLVM compilation architecture, which compiles to LLVM IR
- EMScripten converts LLVM IR to.wASM binary bytecode
- A WebAssembly can’t get the DOM directly. It can only call JS, passing in raw data types such as integers or floating-point types. Therefore, a WebAssembly needs to call JS to get the Web API and call. EMScripten does this by creating HTML files and JS glue code
In the future, WebAssemblies can also call Web apis directly.
The JS glue code above is not as simple as you might think. At first, EMScripten implemented some popular C/C++ libraries such as SDL, OpenGL, OpenAL, and some POSIX libraries based on Web apis. So you need JS glue code to help WebAssembly interact with the underlying Web API.
So, part of the glue code implements the functions of the corresponding libraries that C/C++ code needs to use, and the glue code also contains the logic to call the WebAssembly JavaScript API above to get, load, and run.wasm files.
The generated HTML document loads the JS glue code and writes the output to the
Write WebAssembly code directly
If you want to build your own compiler, toolchain, or JS library that generates WebAssembly code at runtime, you can opt for hand-written WebAssembly code. Like physical assembly, WebAssembly’s binary format has a text representation that you can write or generate manually and convert text to binary using WebAssembly’s text-to-binary tools.
Write Rust code and compile it into WebAssembly
Thanks to the tireless efforts of the Rust WebAssembly Working group, we can now compile Rust code into WebAssembly code.
Check out this link: developer.mozilla.org/en-US/docs/…
Using AssemblyScript
AssemblyScript is the best choice for Web developers who want to try out WebAssembly writing in typescript-like form without learning the details of C or Rust. AssemblyScript compiles TypeScript variants to WebAssembly, allowing Web developers to use typescript-compatible toolchains such as Prettier, VSCode Intellisense, You can check its documentation to see how to use it.
How to compile newly written C/C++ code into WebAssembly?
The EMScripten tool allows you to compile newly written C/C++ code for Use by WebAssembly.
Preparation conditions
In order to be able to use the Emscripten tool, we need to install it. First Clone related code:
git clone https: // github . com / emscripten-core / emsdk . git
cd emsdk
Copy the code
Then execute the following script to configure emSDK:
Git pull /emsdk install latest # Activate the latest SDK tool for the current user. /emsdk activate Latest # Add sdK-related commands to PATH and activate other environment variables source./emsdk_env.shCopy the code
With the above operations, we can use emscripten-related commands at the command line. Generally, there are two scenarios when we use Emscripten:
- Compile to WASM and then create HTML documents to run the code, along with JavaScript glue code to run the WASM code in a Web environment
- Compile to WASM code and create only JavaScript files
Generate HTML and JavaScript
First create a folder in the emSDK directory: WebAssembly, and then create a C code in the folder: hello.c as follows:
#include <stdio.h>
int main() {
printf("Hello World\n");
}
Copy the code
Then navigate to the hello.c directory from the command line and run the following command to invoke Emscripten for compilation:
emcc hello.c -s WASM=1 -o hello.html
Copy the code
The above commands are explained as follows:
emcc
Command line command for Emscripten-s WASM=1
Tells Emscripten that it needs to output the WASM file, which will be output by default if this parameter is not specifiedasm.js
-o hello.html
Tells the compiler to generate a file namedhello.html
To run the code, as well as the WASM module and the corresponding JavaScript glue code for compiling and instantiating WASM so that wASM can be used in a Web environment
After running the command above, you should have three more files in your WebAssembly directory:
- Binary WASM module code:
hello.wasm
- JavaScript file containing glue code:
hello.js
, which translates native C functions into JavaScript/ WASM code - An HTML file:
hello.html
To load, compile, and instantiate wASM code and display the output of the WASM code on the browser.
Run the code
All that’s left to do now is load hello.html in a WebAssembly-enabled browser.
Supported by default in Firefox 52+, Chrome 57+, and the smallest Opera browsers, You can also allow experimentation by enabling javascript.options.wasm in About :config in Firefox 47+ and Chrome ://flags in Chrome 51+ and Opera 38+ WebAssembly special effects support.
Since modern browsers do not support file:// XHR requests, they cannot load.wasm and other related files in HTML, so additional local server support is required to see the effect, by running the following command:
npx serve .
Copy the code
NPX is a convenient tool for NPM command execution launched by NPM after 5.2.0+, such as the above serve, when running, it first checks whether local exists, if not, it downloads the original corresponding package and executes the corresponding command, and it is a one-time operation, which avoids installation before permission. Operations that require temporary use of local memory.
In WebAssembly folder to run a local Web server, and then open the http://localhost:5000/hello.html to check the effect:
You can see that the code we wrote in C to print Hello World is successfully printed in the browser. You can also open the console and see the corresponding output:
Congratulations to you! You’ve compiled a C module into a WebAssembly and run it in a browser!
Use custom HTML templates
The Emscripten default HTML template is used in the above example, but there are many scenarios where you need a custom HTML template, such as integrating WebAssembly into an existing project. Let’s look at how to use custom HTML templates.
Create a new hello2.c file in the WebAssembly directory and write the following:
#include <stdio.h>
int main() {
printf("Hello World\n");
}
Copy the code
Clone the shell_minimal. HTML file from the emSDK repository and copy it to the html_template subfolder in the WebAssembly directory (this folder needs to be created). The file structure in the WebAssembly directory now looks like this:
. ├ ─ ─ hello. C ├ ─ ─ hello. HTML ├ ─ ─ hello. Js ├ ─ ─ hello.html wasm ├ ─ ─ hello2. C └ ─ ─ html_template └ ─ ─ shell_minimal. HTMLCopy the code
Navigate to WebAssembly from the command line and run the following command:
emcc -o hello2.html hello2.c -O3 -s WASM=1 --shell-file html_template/shell_minimal.html
Copy the code
As you can see, there are several changes in parameter passing:
- By setting the
-o hello2.html
, the compiler will outputhello2.js
JS glue code as wellhello2.html
The HTML file - At the same time set
--shell-file html_template/shell_minimal.html
This command provides the address of the HTML template that you will use to generate the HTML file.
Now let’s run the HTML with the following command:
npx serve .
Copy the code
In the browser to navigate to: localhosthttp: / / localhost: 5000 / hello2. HTML to access the run results, before a similar effect can be observed and:
You can see that the Emscripten header is missing, but everything else is the same as before. If you look at the WebAssembly directory, you can see that similar JS and Wasm code is generated:
. ├ ─ ─ hello. C ├ ─ ─ hello. HTML ├ ─ ─ hello. Js ├ ─ ─ hello.html wasm ├ ─ ─ hello2. C ├ ─ ─ hello2. HTML ├ ─ ─ hello2. Js ├ ─ ─ hello2. Wasm └ ─ ─ Html_template └ ─ ─ shell_minimal. HTMLCopy the code
Note: You can specify that only JavaScript glue code is output, rather than a full HTML document, by specifying it as a.js file after the -o tag, such as emcc -o hello2.js hello2.c -o3 -s WASM=1, You can then customize the HTML file and import the glue code to use, however this is a more advanced method and the usual form is to use the supplied HTML template:
-
Emscripten requires a lot of JavaScript glue code to handle memory allocation, memory leaks, and a host of other issues.
Call a custom function in C
If you define a function in C code and want to call it in JavaScript, you can use Emscripten’s ccall function and the EMSCRIPTEN_KEEPALIVE declaration (this declaration adds your C function to the function output list, The specific working process is as follows:
Create a hello3.c file in the WebAssembly directory and add the following:
#include <stdio.h>
#include <emscripten/emscripten.h>
int main() {
printf("Hello World\n");
}
#ifdef __cplusplus
extern "C" {
#endif
EMSCRIPTEN_KEEPALIVE void myFunction(int argc, char ** argv) {
printf("MyFunction Called\n");
}
#ifdef __cplusplus
}
#endif
Copy the code
Emscripten-generated code only calls main by default, and the rest of the functions are removed as “dead code.” Adding the EMSCRIPTEN_KEEPALIVE declaration before the function name prevents this “deletion” from happening. You need to import the emscripten.h header file to use the EMSCRIPTEN_KEEPALIVE declaration.
Note that we have added the #ifdef block to our code to make sure that this works when imported into C++ code, because C and C++ naming may have some confusing rules, so the above function to add EMSCRIPTEN_KEEPALIVE declaration may not work. So add external to the function in C++, treat it as an external function, and it will work in C++.
Then, for the sake of demonstration, the HTML file still uses the shell_minimal. HTML file we put in the html_template directory, and then use the following command to compile the C code:
emcc -o hello3.html hello3.c -O3 -s WASM=1 --shell-file html_template/shell_minimal.html -s NO_EXIT_RUNTIME=1 -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall']"
Copy the code
Note that in the above compilation we added the NO_EXIT_RUNTIME parameter because the program will exit when main is finished, so we added this parameter to ensure that the other functions will still run as expected.
The extra EXTRA_EXPORTED_RUNTIME_METHODS is used to export CCall methods to WebAssembly modules, allowing exported C functions to be called in JavaScript.
When you run it through NPX serve. you can still see similar results:
Now we can try using the myFunction function in JavaScript by opening the hello3. HTML file in the editor, then adding a
<! <button class="mybutton">Run myFunction</button> <script type='text/javascript'> //... Document.queryselector ('.myButton ').addeventListener ('click', function() { alert('check console'); var result = Module.ccall( 'myFunction', // name of C function null, // return type null, // argument types null // arguments ); }); </script> <! -- Other content -->Copy the code
Save the above content and refresh the browser to see the following result:
When we click the button in the image above, we get the following result:
MyFunction Called (” MyFunction Called “); MyFunction Called (” MyFunction Called “);
The above example shows that you can call functions exported from C code in JavaScript via ccall.
How to compile an existing C module into WebAssembly?
A core usage scenario for WebAssembly is to reuse libraries in the existing C ecosystem and compile them for use on the Web platform without having to re-implement a set of code.
These C libraries often rely on C’s standard library, operating system, file system, or other dependencies, and Emscripten provides most of these dependencies, although there are some limitations.
Let’s compile the WebP encoder of the C library into WASM to see how to compile existing C modules. The source code of WebP Codec is implemented in C, which can be found on Github, and some OF its API documents can be seen.
Clone WebP encoder source code to local, and emSDK, WebAssembly directory equivalent:
git clone https://github.com/webmproject/libwebp
Copy the code
To get started, we can import the “WebPGetEncoderVersion” function from the “encode.h” header file to JavaScript. First create the “webp.c” file in the “WebAssembly” folder and add the following:
#include "emscripten.h"
#include "src/webp/encode.h"
EMSCRIPTEN_KEEPALIVE
int version() {
return WebPGetEncoderVersion();
}
Copy the code
The above example is a quick way to verify that the source code for libwebp is compiled correctly and that its functions can be used successfully, since the above functions can be executed successfully without complicated arguments and data structures.
To compile the above function, we first have to tell the compiler how to find the libwebp library header file, tell the compiler the address by adding the flag I at compile time, then specify the location of the libwep header file, and pass it all the C files in libwebp that the compiler needs. An effective strategy is to pass all C files to the compiler and rely on the compiler itself to filter out unnecessary files. This can be done by writing the following command on the command line:
emcc -O3 -s WASM=1 -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap"]' \
-I libwebp \
WebAssembly/webp.c \
libwebp/src/{dec,dsp,demux,enc,mux,utils}/*.c
Copy the code
Note: Many projects rely on libraries such as Autoconfig/Automake to generate system-specific code before compiling. Emscripten provides emconfigure and Emmake to encapsulate these commands. And inject appropriate parameters to smooth out projects that have pre-dependencies.
This will produce a copy of the a.ut.js glue code and the a.ut.wasm file. Then you need to create an HTML file in the output directory of the A.ut.js file and add the following code to it
<script src="./a.out.js"></script>
<script>
Module.onRuntimeInitialized = async _ => {
const api = {
version: Module.cwrap('version', 'number', []),
};
console.log(api.version());
};
</script>
Copy the code
After the WebAssembly module is initialized, use the cwrap function to export the C function version to use, by running the similar NPX serve. Command, and then open the browser to see the following effect:
Libwebp uses the ABC of 0xabc in hexadecimal to represent the current version A.B.C. For example, v0.6.1 is encoded as 0x000601 in hexadecimal and 1537 in decimal. The value is 66049 in decimal and 0x010201 in hexadecimal, indicating that the current version is V1.2.1.
Get the image in JavaScript and run it in WASM
Having just verified that the libwebp library has been successfully compiled into WASM by calling the encoder’s WebPGetEncoderVersion method to get the version number, and can then be used in JavaScript, we’ll move on to more complicated operations, How to convert image formats using libwebp’s coding API.
Libwebp’s Encoding API needs to accept an array of bytes for RGB, RGBA, BGR, or BGRA, so the first question to answer is, how do you put images into WASM to run? Fortunately, the Canvas API have a CanvasRenderingContext2D getImageData method, can return a Uint8ClampedArray, the array contains RGBA image data format.
First we need to write a function to load the image in JavaScript and write it to the HTML file created in the previous step:
<script src="./a.out.js"></script> <script> Module.onRuntimeInitialized = async _ => { const api = { version: Module.cwrap('version', 'number', []), }; console.log(api.version()); }; Async function loadImage(SRC) {const imgBlob = await fetch(SRC).then(resp => resp.blob()); const img = await createImageBitmap(imgBlob); Const canvas = document.createElement('canvas'); const canvas = document.createElement('canvas'); canvas.width = img.width; canvas.height = img.height; // Draw the image to canvas const CTX = Canvas.getContext ('2d'); ctx.drawImage(img, 0, 0); return ctx.getImageData(0, 0, img.width, img.height); } </script>Copy the code
Now all that remains is how to copy image data from JavaScript to WASM. To do this, we need to expose additional methods in the previous webp.c function:
- A method to allocate memory for images in WASM
- A way to free up memory
Modify webp.c as follows:
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); }Copy the code
1 uint8_t (uint8_t); malloc (); When this pointer is returned to JavaScript for use, it is treated as a simple number. When the corresponding C function exposed to JavaScript is retrieved via the cwrap function, you can use this pointer number to find where the memory to copy the image data starts.
We added additional code to the HTML file as follows:
<script src="./a.out.js"></script> <script> 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", []), }; const image = await loadImage('./image.jpg'); const p = api.create_buffer(image.width, image.height); Module.HEAP8.set(image.data, p); / /... call encoder ... api.destroy_buffer(p); }; Async function loadImage(SRC) {const imgBlob = await fetch(SRC).then(resp => resp.blob()); const img = await createImageBitmap(imgBlob); Const canvas = document.createElement('canvas'); const canvas = document.createElement('canvas'); canvas.width = img.width; canvas.height = img.height; // Draw the image to canvas const CTX = Canvas.getContext ('2d'); ctx.drawImage(img, 0, 0); return ctx.getImageData(0, 0, img.width, img.height); } </script>Copy the code
As you can see, in addition to importing the create_buffer and Destroy_buffer we added earlier, the code also has many functions for encoding files, which we’ll cover later. In addition, the code first loads an image of image.jpg. We then call C to allocate memory for the image data, get the corresponding pointer to the WebAssembly Module.HEAP8, write the image data at the beginning of memory, and finally free the allocated memory.
Coding image
Now that the image data has been loaded into WASM’s memory, you can call the libwebp encoder method to complete the coding process. Looking at the WebP documentation, you can use the WebPEncodeRGBA function to do the work. This function takes a pointer to the image data and its size, along with an optional quality parameter ranging from 0 to 100. During coding, WebPEncodeRGBA allocates a block of memory for output data, and we need to call WebPFree to free this memory after coding.
We open the webp.c file and add the following code to handle the encoding:
int result[2];
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];
}
Copy the code
The result of the above WebPEncodeRGBA function is to allocate a block of memory for the output data and the size of the returned memory. Array because C function cannot be used as the return value (unless we need to carry on the dynamic memory allocation), so we use a global static array to obtain the results returned, it may not be very normative writing C code, at the same time it requires wasm pointer to 32 – bit, but for the sake of simplicity we can tolerate this kind of practice for the time being.
Now that the c-side logic has been written, you can call the encoding function on the JavaScript side to get the pointer to the image data and the memory occupied by the image, save this data in JavaScript’s own memory, and then release the memory allocated by WASM when processing the image. Let’s open the HTML file to complete the logic described above:
<script src="./a.out.js"></script> <script> 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", []), }; const image = await loadImage('./image.jpg'); const p = api.create_buffer(image.width, image.height); Module.HEAP8.set(image.data, p); api.encode(p, image.width, image.height, 100); const resultPointer = api.get_result_pointer(); const resultSize = api.get_result_size(); const resultView = new Uint8Array(Module.HEAP8.buffer, resultPointer, resultSize); const result = new Uint8Array(resultView); api.free_result(resultPointer); api.destroy_buffer(p); }; Async function loadImage(SRC) {const imgBlob = await fetch(SRC).then(resp => resp.blob()); const img = await createImageBitmap(imgBlob); Const canvas = document.createElement('canvas'); const canvas = document.createElement('canvas'); canvas.width = img.width; canvas.height = img.height; // Draw the image to canvas const CTX = Canvas.getContext ('2d'); ctx.drawImage(img, 0, 0); return ctx.getImageData(0, 0, img.width, img.height); } </script>Copy the code
In the above code we load a local image.jpg image using the loadImage function. You need to prepare an image to use in the emCC compiler’s output directory, which is our HTML file directory.
Note: New Uint8Array(someBuffer) will create a new view on the same memory block, while new Uint8Array(someTypedArray) will only copy the data of someTypedArray.
When your image is large, because WASM cannot expand the memory that can hold the input and output image data, you may get the following error:
However, the image used in our example is small, so simply add a filter parameter -s ALLOW_MEMORY_GROWTH=1 at compile time and ignore the error message:
emcc -O3 -s WASM=1 -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap"]' \
-I libwebp \
test-dir/webp.c \
libwebp/src/{dec,dsp,demux,enc,mux,utils}/*.c \
-s ALLOW_MEMORY_GROWTH=1
Copy the code
Running the above command again yields the wASM code with the encoding function added and the corresponding JavaScript glue code, so that when we open the HTML file, it is already able to encode a JPG file into WebP format. To further prove this point, We can display the image on the Web interface by modifying the HTML file and adding the following code:
<script> // ... api.encode(p, image.width, image.height, 100); const resultPointer = api.get_result_pointer(); const resultSize = api.get_result_size(); 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 img = document.createElement('img'); img.src = blobURL; document.body.appendChild(img) api.free_result(resultPointer); api.destroy_buffer(p); </script>Copy the code
Then refresh the browser and you should see the WebP image displayed on the Web side. By downloading the file locally, you can see the format changed to WebP:
We successfully compiled the existing libwebp C library into WASM, and converted JPG images into WebP format and displayed them on the Web interface. Using WASM to handle computation-intensive transcoding operations can greatly improve the performance of Web pages. This is one of the main advantages WebAssembly brings.
Thank you for support
That is all the content of this sharing. I hope it will help you
Don’t forget to share, like and bookmark your favorite things
Welcome to pay attention to the public number programmer bus, an interesting, stylish, temperature programmer bus, dabin dachang face, programmer life, actual combat tutorial, technology and other content, pay attention to me, make a friend!