WebAssembly 系列(三):图片解码 webp实践 2

1,908 阅读3分钟

ios web 前端支持 webP 的 WebAssembly 方案 --环境搭建与编译(一)

ios safari webp 图片优化之 WebAssembly 移植谷歌开源库 libwebp 到 web 应用

前言

libwebp编译成JavaScript解码器的过程 使用EmscriptenCMake。下文主要记录 macEmscriptenCMake的安装,编译libwebp --> webp_wasm.js + webp_wasm.wasm完整过程。

一、下载安装 Emscripten SDK 简称 emsdk

由于Emscripten SDK (emsdk)是用 Python 写的, 相关依赖也是从python.org 下载,需要有 python 环境 。首先需要查看本地 Python 版本,安装 pip ( 官方) 。

第一步:查看 python 的版本

Mac电脑自带python环境,打开终端,输入python,按下enter键,查看自己电脑中的python版本(默认安装的是python2.7版本)【提示:查看完python的版本后,输入exit(),或者quit()即可退出终端中的python环境】。 但是在开发时,我们多数使用的是 python3,在终端中输入python3,按下enter键,查看电脑中是否装有python3。如果电脑中没有安装python3,可以去python官网下载。https://www.python.org/downloads/release/python-363/。 下载后安装python3,一直点击下一步即可。安装完成后,在终端中输入python3,查看是否安装成功。 python3安装完成后,我们下载python的一些扩展包的时候需要使用pip3 install命令,如需下载ipython扩展包,在终端命令行中输入pip3 install ipython,按下enter即可自动安装。【输入pip3 list可以查看当前python环境中安装了哪些扩展包】


# 退出 python 环境 
 quit()
 
# 查看 python2 版本
 python
 
# 下载 get-pip.py
 curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
 
# 运行安装脚本 (注意:用哪个版本的 Python 运行安装脚本,pip 就被关联到哪个版本,如果是 Python3 则执行以下命令)
 sudo python get-pip.py
 
# 安装证书(避免终端下载 `python` 包失败)
 pip install certifi
 
 

# 如何是 python3 请看👇
# 查看 python3 的版本
 python3
 sudo python3 get-pip.py


查看 python3 的版本

python2 查看版本的方式

pip 安装成功

第二步:安装 emsdk

# Get the emsdk repo
git clone https://github.com/emscripten-core/emsdk.git

# Enter that directory
cd emsdk

git pull

# Download and install the latest SDK tools. 这个过程有点久~需要耐心等待
./emsdk install latest

# Make the "latest" SDK "active" for the current user. (writes ~/.emscripten file)
./emsdk activate latest

# Activate PATH and other environment variables in the current terminal (这步很重要!!!每次修改环境变量都要执行使之生效)
source ./emsdk_env.sh

# $EMSCRIPTEN should point to the top-level directory containing Emscripten tools (添加环境变量,让 emcc 的命令可以在任意目录使用)
vim ~/.bash_profile 

## 在 bash_profile 最后
export EMSCRIPTEN=$EMSDK/upstream/emscripten
export EMSDK="/Users/zhangxj/Desktop/workspace/demo/libwebp-demo/emsdk"
export EM_CONFIG="/Users/zhangxj/.emscripten"
export EMSCRIPTEN="$EMSDK/upstream/emscripten"
export EMSDK_NODE="/Users/zhangxj/Desktop/workspace/demo/libwebp-demo/emsdk/node/12.9.1_64bit/bin/node"
PATH="$EMSDK:${PATH}"
PATH="$EMSCRIPTEN:${PATH}"
PATH="$EMSDK_NODE:${PATH}"
export PATH

source ~/.bash_profile

./emsdk install latest

添加环境变量,让 emcc 的命令可以在任意目录使用

附:emsdk 安装过程常见错误 Q&A

Q1: pip 证书没安装

Q2: 安装 pip 需要加 sudo,正确姿势:sudo python get-pip.py

第三步:安装 cmake download


$ cd ~
$ vim .bash_profile

## 添加 cmake 环境变量到 bash_profile
export CMAKE_ROOT=/Applications/CMake.app/Contents/bin/
export PATH=$CMAKE_ROOT:$PATH

$ source ./.bash_profile

$ cmake --version 

## 到 libwep 的源目录,让CMake使用emcc命令作为Compiler和LinkTool
$ cd webp_js && \
 cmake -DWEBP_BUILD_WEBP_JS=ON \
       -DEMSCRIPTEN_GENERATE_BITCODE_STATIC_LIBRARIES=1 \
       -DCMAKE_TOOLCHAIN_FILE=$EMSCRIPTEN/cmake/Modules/Platform/Emscripten.cmake \
       ../

执行完

$libwebp git:(master) cd webp_js && \
 cmake -DWEBP_BUILD_WEBP_JS=ON \
       -DEMSCRIPTEN_GENERATE_BITCODE_STATIC_LIBRARIES=1 \
       -DCMAKE_TOOLCHAIN_FILE=$EMSCRIPTEN/cmake/Modules/Platform/Emscripten.cmake \
       ../
CMake Warning (dev) at CMakeLists.txt:45 (set):
  implicitly converting 'Build type: Release, Debug, MinSizeRel or
  RelWithDebInfo' to 'STRING' type.
This warning is for project developers.  Use -Wno-dev to suppress it.

-- Performing Test HAVE_BUILTIN_BSWAP16
-- Performing Test HAVE_BUILTIN_BSWAP16 - Success
-- Performing Test HAVE_BUILTIN_BSWAP32
-- Performing Test HAVE_BUILTIN_BSWAP32 - Success
-- Performing Test HAVE_BUILTIN_BSWAP64
-- Performing Test HAVE_BUILTIN_BSWAP64 - Success
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
-- Found Threads: TRUE  
-- Performing Test HAVE_PTHREAD_PRIO_INHERIT
-- Performing Test HAVE_PTHREAD_PRIO_INHERIT - Success
-- Performing Test PTHREAD_CREATE_UNDETACHED
-- Performing Test PTHREAD_CREATE_UNDETACHED - Success
-- Performing Test HAVE_MATH_LIBRARY
-- Performing Test HAVE_MATH_LIBRARY - Success
-- Could NOT find ZLIB (missing: ZLIB_LIBRARY ZLIB_INCLUDE_DIR) 
-- Could NOT find PNG (missing: PNG_LIBRARY PNG_PNG_INCLUDE_DIR) 
-- Could NOT find JPEG (missing: JPEG_LIBRARY JPEG_INCLUDE_DIR) 
-- Could NOT find TIFF (missing: TIFF_LIBRARY TIFF_INCLUDE_DIR) 
-- Could NOT find GIF (missing: GIF_LIBRARY GIF_INCLUDE_DIR) 
-- Looking for 4 include files stdlib.h, ..., float.h
-- Looking for 4 include files stdlib.h, ..., float.h - found
-- Looking for include file dlfcn.h
-- Looking for include file dlfcn.h - found
-- Looking for include file GLUT/glut.h
-- Looking for include file GLUT/glut.h - not found
-- Looking for include file GL/glut.h
-- Looking for include file GL/glut.h - found
-- Looking for include file inttypes.h
-- Looking for include file inttypes.h - found
-- Looking for include file memory.h
-- Looking for include file memory.h - found
-- Looking for include file OpenGL/glut.h
-- Looking for include file OpenGL/glut.h - not found
-- Looking for include file shlwapi.h
-- Looking for include file shlwapi.h - not found
-- Looking for include file stdint.h
-- Looking for include file stdint.h - found
-- Looking for include file stdlib.h
-- Looking for include file stdlib.h - found
-- Looking for include file strings.h
-- Looking for include file strings.h - found
-- Looking for include file string.h
-- Looking for include file string.h - found
-- Looking for include file sys/stat.h
-- Looking for include file sys/stat.h - found
-- Looking for include file sys/types.h
-- Looking for include file sys/types.h - found
-- Looking for include file unistd.h
-- Looking for include file unistd.h - found
-- Looking for include file wincodec.h
-- Looking for include file wincodec.h - not found
-- Looking for include file windows.h
-- Looking for include file windows.h - not found
-- Disabling SSE41 optimization.
-- Disabling SSE41 optimization.
-- Performing Test HAS_COMPILE_FLAG
-- Performing Test HAS_COMPILE_FLAG - Success
-- Performing Test FLAG_-mno-sse4.1
-- Performing Test FLAG_-mno-sse4.1 - Failed
-- Disabling SSE2 optimization.
-- Disabling SSE2 optimization.
-- Performing Test HAS_COMPILE_FLAG
-- Performing Test HAS_COMPILE_FLAG - Success
-- Performing Test FLAG_-mno-sse2
-- Performing Test FLAG_-mno-sse2 - Failed
-- Disabling MIPS32 optimization.
-- Disabling MIPS32 optimization.
-- Disabling MIPS_DSP_R2 optimization.
-- Disabling MIPS_DSP_R2 optimization.
-- Performing Test HAS_COMPILE_FLAG
-- Performing Test HAS_COMPILE_FLAG - Success
-- Performing Test FLAG_-mno-dspr2
-- Performing Test FLAG_-mno-dspr2 - Failed
-- Disabling NEON optimization.
-- Disabling NEON optimization.
-- Disabling MSA optimization.
-- Disabling MSA optimization.
-- Performing Test HAS_COMPILE_FLAG
-- Performing Test HAS_COMPILE_FLAG - Success
-- Performing Test FLAG_-mno-msa
-- Performing Test FLAG_-mno-msa - Failed
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/zhangxj/Desktop/workspace/demo/libwebp/webp_js

# 最后一步,到 webp_js 目录下 执行
$ make

Q & A

  • Q1:为什么改了 配置编译编译没生效?

  • A1:cmake 的工程,每次执行 cmake 需要清除,cd webp_js && git clean -dxf .

  • Q2:make 编译过程出现报错--share--memory mused to be use

  • A2:尝试去掉 -DEMSCRIPTEN_GENERATE_BITCODE_STATIC_LIBRARIES=1,换成这个 cd webp_js && git clean -dxf . && cmake -DWEBP_BUILD_WEBP_JS=ON -DCMAKE_TOOLCHAIN_FILE=$EMSCRIPTEN/cmake/Modules/Platform/Emscripten.cmake ../

--share--memory mused to be use 报错的截图

--share--memory mused to be use

make 成功编译好了

编译前后对比 webp_js 文件目录对比

# 编译前
$ webp_js git:(master) ✗ tree .
.
├── index.html
├── index_wasm.html
├── test_webp_js.webp
└── test_webp_wasm.webp

0 directories, 4 files

# 编译后
$ webp_js git:(master) ✗ tree .
.
├── CMakeCache.txt
├── CMakeFiles
│   ├── 3.16.1
│   │   ├── CMakeCCompiler.cmake
│   │   └── CMakeSystem.cmake
│   ├── CMakeDirectoryInformation.cmake
│   ├── CMakeError.log
│   ├── CMakeOutput.log
│   ├── CMakeTmp
│   ├── CheckIncludeFiles
│   │   ├── HAVE_DLFCN_H.c
│   │   ├── HAVE_GLUT_GLUT_H.c
│   │   ├── HAVE_GL_GLUT_H.c
│   │   ├── HAVE_INTTYPES_H.c
│   │   ├── HAVE_MEMORY_H.c
│   │   ├── HAVE_OPENGL_GLUT_H.c
│   │   ├── HAVE_SHLWAPI_H.c
│   │   ├── HAVE_STDINT_H.c
│   │   ├── HAVE_STDLIB_H.c
│   │   ├── HAVE_STRINGS_H.c
│   │   ├── HAVE_STRING_H.c
│   │   ├── HAVE_SYS_STAT_H.c
│   │   ├── HAVE_SYS_TYPES_H.c
│   │   ├── HAVE_UNISTD_H.c
│   │   ├── HAVE_WINCODEC_H.c
│   │   ├── HAVE_WINDOWS_H.c
│   │   └── STDC_HEADERS.c
│   ├── Export
│   │   └── share
│   │       └── WebP
│   │           └── cmake
│   │               ├── WebPTargets-release.cmake
│   │               └── WebPTargets.cmake
│   ├── Makefile.cmake
│   ├── Makefile2
│   ├── TargetDirectories.txt
│   ├── cmake.check_cache
│   ├── progress.marks
│   ├── webp.dir
│   │   ├── DependInfo.cmake
│   │   ├── build.make
│   │   ├── cmake_clean.cmake
│   │   ├── cmake_clean_target.cmake
│   │   ├── depend.internal
│   │   ├── depend.make
│   │   ├── flags.make
│   │   ├── includes_C.rsp
│   │   ├── link.txt
│   │   ├── objects1.rsp
│   │   └── progress.make
│   ├── webp_js.dir
│   │   ├── C.includecache
│   │   ├── DependInfo.cmake
│   │   ├── build.make
│   │   ├── cmake_clean.cmake
│   │   ├── depend.internal
│   │   ├── depend.make
│   │   ├── extras
│   │   │   └── webp_to_sdl.c.o
│   │   ├── flags.make
│   │   ├── includes_C.rsp
│   │   ├── link.txt
│   │   ├── linklibs.rsp
│   │   ├── objects1.rsp
│   │   └── progress.make
│   ├── webp_wasm.dir
│   │   ├── C.includecache
│   │   ├── DependInfo.cmake
│   │   ├── build.make
│   │   ├── cmake_clean.cmake
│   │   ├── depend.internal
│   │   ├── depend.make
│   │   ├── extras
│   │   │   └── webp_to_sdl.c.o
│   │   ├── flags.make
│   │   ├── includes_C.rsp
│   │   ├── link.txt
│   │   ├── linklibs.rsp
│   │   ├── objects1.rsp
│   │   └── progress.make
│   ├── webpdecode.dir
│   │   ├── C.includecache
│   │   ├── DependInfo.cmake
│   │   ├── build.make
│   │   ├── cmake_clean.cmake
│   │   ├── depend.internal
│   │   ├── depend.make
│   │   ├── flags.make
│   │   ├── includes_C.rsp
│   │   ├── progress.make
│   │   └── src
│   │       └── dec
│   │           ├── alpha_dec.c.o
│   │           ├── buffer_dec.c.o
│   │           ├── frame_dec.c.o
│   │           ├── idec_dec.c.o
│   │           ├── io_dec.c.o
│   │           ├── quant_dec.c.o
│   │           ├── tree_dec.c.o
│   │           ├── vp8_dec.c.o
│   │           ├── vp8l_dec.c.o
│   │           └── webp_dec.c.o
│   ├── webpdecoder.dir
│   │   ├── DependInfo.cmake
│   │   ├── build.make
│   │   ├── cmake_clean.cmake
│   │   ├── cmake_clean_target.cmake
│   │   ├── depend.internal
│   │   ├── depend.make
│   │   ├── flags.make
│   │   ├── includes_C.rsp
│   │   ├── link.txt
│   │   ├── objects1.rsp
│   │   └── progress.make
│   ├── webpdemux.dir
│   │   ├── C.includecache
│   │   ├── DependInfo.cmake
│   │   ├── build.make
│   │   ├── cmake_clean.cmake
│   │   ├── cmake_clean_target.cmake
│   │   ├── depend.internal
│   │   ├── depend.make
│   │   ├── flags.make
│   │   ├── includes_C.rsp
│   │   ├── link.txt
│   │   ├── objects1.rsp
│   │   ├── progress.make
│   │   └── src
│   │       └── demux
│   │           ├── anim_decode.c.o
│   │           └── demux.c.o
│   ├── webpdsp.dir
│   │   ├── C.includecache
│   │   ├── DependInfo.cmake
│   │   ├── build.make
│   │   ├── cmake_clean.cmake
│   │   ├── depend.internal
│   │   ├── depend.make
│   │   ├── flags.make
│   │   ├── includes_C.rsp
│   │   ├── progress.make
│   │   └── src
│   │       └── dsp
│   │           ├── alpha_processing.c.o
│   │           ├── cost.c.o
│   │           ├── cpu.c.o
│   │           ├── dec.c.o
│   │           ├── dec_clip_tables.c.o
│   │           ├── enc.c.o
│   │           ├── filters.c.o
│   │           ├── lossless.c.o
│   │           ├── lossless_enc.c.o
│   │           ├── rescaler.c.o
│   │           ├── ssim.c.o
│   │           ├── upsampling.c.o
│   │           └── yuv.c.o
│   ├── webpdspdecode.dir
│   │   ├── C.includecache
│   │   ├── DependInfo.cmake
│   │   ├── build.make
│   │   ├── cmake_clean.cmake
│   │   ├── depend.internal
│   │   ├── depend.make
│   │   ├── flags.make
│   │   ├── includes_C.rsp
│   │   ├── progress.make
│   │   └── src
│   │       └── dsp
│   │           ├── alpha_processing.c.o
│   │           ├── cpu.c.o
│   │           ├── dec.c.o
│   │           ├── dec_clip_tables.c.o
│   │           ├── filters.c.o
│   │           ├── lossless.c.o
│   │           ├── rescaler.c.o
│   │           ├── upsampling.c.o
│   │           └── yuv.c.o
│   ├── webpencode.dir
│   │   ├── C.includecache
│   │   ├── DependInfo.cmake
│   │   ├── build.make
│   │   ├── cmake_clean.cmake
│   │   ├── depend.internal
│   │   ├── depend.make
│   │   ├── flags.make
│   │   ├── includes_C.rsp
│   │   ├── progress.make
│   │   └── src
│   │       └── enc
│   │           ├── alpha_enc.c.o
│   │           ├── analysis_enc.c.o
│   │           ├── backward_references_cost_enc.c.o
│   │           ├── backward_references_enc.c.o
│   │           ├── config_enc.c.o
│   │           ├── cost_enc.c.o
│   │           ├── filter_enc.c.o
│   │           ├── frame_enc.c.o
│   │           ├── histogram_enc.c.o
│   │           ├── iterator_enc.c.o
│   │           ├── near_lossless_enc.c.o
│   │           ├── picture_csp_enc.c.o
│   │           ├── picture_enc.c.o
│   │           ├── picture_psnr_enc.c.o
│   │           ├── picture_rescale_enc.c.o
│   │           ├── picture_tools_enc.c.o
│   │           ├── predictor_enc.c.o
│   │           ├── quant_enc.c.o
│   │           ├── syntax_enc.c.o
│   │           ├── token_enc.c.o
│   │           ├── tree_enc.c.o
│   │           ├── vp8l_enc.c.o
│   │           └── webp_enc.c.o
│   ├── webputils.dir
│   │   ├── C.includecache
│   │   ├── DependInfo.cmake
│   │   ├── build.make
│   │   ├── cmake_clean.cmake
│   │   ├── depend.internal
│   │   ├── depend.make
│   │   ├── flags.make
│   │   ├── includes_C.rsp
│   │   ├── progress.make
│   │   └── src
│   │       └── utils
│   │           ├── bit_reader_utils.c.o
│   │           ├── bit_writer_utils.c.o
│   │           ├── color_cache_utils.c.o
│   │           ├── filters_utils.c.o
│   │           ├── huffman_encode_utils.c.o
│   │           ├── huffman_utils.c.o
│   │           ├── quant_levels_dec_utils.c.o
│   │           ├── quant_levels_utils.c.o
│   │           ├── random_utils.c.o
│   │           ├── rescaler_utils.c.o
│   │           ├── thread_utils.c.o
│   │           └── utils.c.o
│   └── webputilsdecode.dir
│       ├── C.includecache
│       ├── DependInfo.cmake
│       ├── build.make
│       ├── cmake_clean.cmake
│       ├── depend.internal
│       ├── depend.make
│       ├── flags.make
│       ├── includes_C.rsp
│       ├── progress.make
│       └── src
│           └── utils
│               ├── bit_reader_utils.c.o
│               ├── color_cache_utils.c.o
│               ├── filters_utils.c.o
│               ├── huffman_utils.c.o
│               ├── quant_levels_dec_utils.c.o
│               ├── random_utils.c.o
│               ├── rescaler_utils.c.o
│               ├── thread_utils.c.o
│               └── utils.c.o
├── Makefile
├── WebPConfig.cmake
├── WebPConfigVersion.cmake
├── cmake_install.cmake
├── index.html
├── index_wasm.html
├── libwebp.a
├── libwebpdecoder.a
├── libwebpdemux.a
├── src
│   ├── demux
│   │   └── libwebpdemux.pc
│   ├── libwebp.pc
│   ├── libwebpdecoder.pc
│   └── webp
│       └── config.h
├── test_webp_js.webp
├── test_webp_wasm.webp
├── webp.js
├── webp.wasm
├── webp.worker.js
├── webp_wasm.js
├── webp_wasm.wasm
└── webp_wasm.worker.js

38 directories, 243 files

测试一下

# webp_js 目录下 ,启动服务
$ http-server

能成功访问使用 webp_wasm.js 和 webp_wasm.wasm 啦

后言

想要了解一下,webpack 工程如何使用 web_wasm.jsweb_wasm.wasm,请移步下一篇文章 ios web 前端支持 webP 的 WebAssembly 方案 -- 结合 webpack ios web 生产环境应用 webp(二) (待写),先放一个已完成并应用到生产环境 webp-decode的js库。

这是一整个系列文章,定期更新

参考文章