[Emscripten+WebGL] jpg/jpeg image viewer

source code: https://github.com/svoisen/wasm-imageviewer.git

Makefile:

CFLAGS=-Werror -std=c++11 -O1 -g0
EMSCRIPTEN_FLAGS=-s FULL_ES3=1 \
-s USE_SDL=2 \
-s WASM=1 \
-s GL_DEBUG=1 \
-s TOTAL_MEMORY=134217728 \
-s EXTRA_EXPORTED_RUNTIME_METHODS=”[‘ccall’, ‘cwrap’]” \
-s EXPORTED_FUNCTIONS='[“_initializeOpenGL”, “_render”, “_loadJPEGImage”]’

由于这个demo问题比较多,所以打开了debug,然后优化也只用O1,尚不清楚FULL_ES3=1是不是必要的,有待验证

renderer.cpp改动:

1)出错信息打印:

    if (!shaderCompiled) {
      GLint infoLen = 0;
      glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );
      if ( infoLen > 1 )
      {
                // 原文件这里只是简单输出字符串,改成拿具体的出错信息,错误会比较清楚
		char *infoLog = (char *) malloc ( sizeof ( char ) * infoLen );
		glGetShaderInfoLog ( shader, infoLen, NULL, infoLog );
		std::cerr << "Error compiling shader:" << std::endl << infoLog;
		free ( infoLog );
      }
      glDeleteShader ( shader );
      return 0;
    }

2)编译之后的renderer.js
“webgl”改成”webgl2″!这个重要!

因为之前编译后运行起来提示:
ERROR: unsupported shader version
搞不懂为什么,寻思可能cpp中的shader头写的不对?

参考【1】说:#version 300 es必须顶格写!所以

<script type="x-shader/x-vertex" id="vertex-shader">
#version 300 es
...
</script>

是错误的!
正确是

<script type="x-shader/x-vertex" id="vertex-shader">#version 300 es
...
</script>

<scritpt>后面没有换行!

把cpp各种修改,都没啥效果,看了参考【2】,也是这么写的,没问题。

后来想,既然是初始化出问题,那把这个c代码的初始化改写成简单的html+js,看看怎么样。

html内容:

<!DOCTYPE html>
<html><body>
  <div id="container" class="container">
    <canvas id="canvas" class="canvas"></canvas>
  </div>
<script type="x-shader/x-vertex" id="vertex-shader">#version 300 es
uniform float zoom;                                                       
uniform float aspect;                                                     
in vec4 vert;                                                             
out vec2 texCoord;                                                        
void main() {
   gl_Position = vec4(vert.x * zoom, vert.y * aspect * zoom, 0.0f, 1.0f);
   texCoord = vec2((vert.x + 1.0f) / 2.0f, (1.0f - vert.y) / 2.0);
}</script>
	<script type="x-shader/x-fragment" id="fragment-shader">#version 300 es
precision mediump float;
uniform sampler2D tex;
vec2 texCoord;
vec4 finalColor;
void main() {                          
   finalColor = texture(tex, texCoord);
}</script>
  <script src="1.js"></script>
</body></html>

1.js内容:

;(function(){
"use strict"
window.addEventListener("load", setupWebGL, false);
var gl,
  program;
function setupWebGL (evt) {
  window.removeEventListener(evt.type, setupWebGL, false);
  if (!(gl = getRenderingContext()))
    return;

  var source = document.querySelector("#vertex-shader").innerHTML;
  var vertexShader = gl.createShader(gl.VERTEX_SHADER);
  gl.shaderSource(vertexShader,source);
  gl.compileShader(vertexShader);
  source = document.querySelector("#fragment-shader").innerHTML
  var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
  gl.shaderSource(fragmentShader,source);
  gl.compileShader(fragmentShader);
  program = gl.createProgram();
  gl.attachShader(program, vertexShader);
  gl.attachShader(program, fragmentShader);
  gl.linkProgram(program);
  gl.detachShader(program, vertexShader);
  gl.detachShader(program, fragmentShader);
  gl.deleteShader(vertexShader);
  gl.deleteShader(fragmentShader);
  if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
    var linkErrLog = gl.getProgramInfoLog(program);
    cleanup();
    document.querySelector("p").innerHTML =
      "Shader program did not link successfully. "
      + "Error log: " + linkErrLog;
    return;
  }

  initializeAttributes();

  gl.useProgram(program);
  gl.drawArrays(gl.POINTS, 0, 1);

  cleanup();
}

var buffer;
function initializeAttributes() {
  gl.enableVertexAttribArray(0);
  buffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.vertexAttribPointer(0, 1, gl.FLOAT, false, 0, 0);
}

function cleanup() {
gl.useProgram(null);
if (buffer)
  gl.deleteBuffer(buffer);
if (program)
  gl.deleteProgram(program);
}
function getRenderingContext() {
  var canvas = document.querySelector("canvas");
  canvas.width = canvas.clientWidth;
  canvas.height = canvas.clientHeight;
  var gl = canvas.getContext("webgl2");
  
  if(!gl)
    gl = canvas.getContext("experimental-webgl");
  if (!gl) {
    var paragraph = document.querySelector("p");
    paragraph.innerHTML = "Failed to get WebGL context."
      + "Your browser or device may not support WebGL.";
    return null;
  }
  gl.viewport(0, 0,
    gl.drawingBufferWidth, gl.drawingBufferHeight);
  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT);
  return gl;
}
})();

关键就在于:
webgl1是 canvas.getContext(“webgl“);
webgl2是canvas.getContext(“webgl2“);

所以,把编译好的renderer.js里面”webgl”改成”webgl2″,就ok了!这个bug对初学者来说有点难度。这里记一个解决的过程。

 

 


第二天接着玩,换了台机器,发现照上面做了还是不行
自己做个最简单的canvas然后canvas.getContext(‘webgl2’)都不行,返回的是null
canvas.getContext(‘webgl’)是可以的,然后换Firefox是可以的,所以判断是chrome的flag哪里不对。于是一个个是过去,发现这个:

Choose ANGLE graphics backend
Choose the graphics backend for ANGLE. D3D11 is used on most Windows computers by default. Using the OpenGL driver as the graphics backend may result in higher performance in some graphics-heavy applications, particularly on NVIDIA GPUs. It can increase battery and memory usage of video playback. – Windows

它有四个选项:
Default(默认)
OpenGL
D3D11
D3D9

改成OpenGL就好了。

 

再一次试了下编译,发现这样的编译选项,编译后的js就可以有getContext(‘webgl2’),不用再改js。

emcc renderer.cpp -Werror -std=c++11 -O0 -g0 -s USE_SDL=2 -s USE_WEBGL2=1 -s FULL_ES3=1 -s GL_DEBUG=1 -s WASM=1 -s TOTAL_MEMORY=134217728 -s EXPORTED_FUNCTIONS=”[‘_initializeOpenGL’, ‘_render’, ‘_loadJPEGImage’]” -s EXTRA_EXPORTED_RUNTIME_METHODS=”[‘ccall’, ‘cwrap’]” –post-js renderer_post.js -o renderer.js

然而最后运行的结果却是还不行,调试的时候看到:
var ctx =
(webGLContextAttributes.majorVersion > 1) ? canvas.getContext(“webgl2”, webGLContextAttributes) :
(canvas.getContext(“webgl”, webGLContextAttributes) || canvas.getContext(“experimental-webgl”, webGLContextAttributes));

这个majorVersion总是1,看了下参考2,它的c代码用的是egl,不一样。感觉已经不是编译选项的问题了,要改代码。又去问度娘,问谷歌,最后在renderer.cpp上加一句:
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
再编译就行了!默认值是2,然后js里面会再减1,所以webGLContextAttributes.majorVersion就是1,然后就悲剧了。

 

 

 

参考:
【1】https://segmentfault.com/a/1190000012002453
【2】https://github.com/danginsburg/opengles3-book.git

tiff2bmpsw using libtiff wasm

git source: https://github.com/horo-t/tiff2bmpsw.git

WebAssembly实现tiff转bmp(使用libtiff库)
1) download source:
http://download.osgeo.org/libtiff/tiff-4.0.9.tar.gz
2) 解压、patch
tar xvfz tiff-4.0.9.tar.gz
cd tiff-4.0.9
patch -u libtiff/tiff.h < ../tiff_h_int_size.patch
3)编译libtiff
emconfigure
emmake make
4)编译tiff2bmp
cd..
emcc tiff2bmpsw.c \
./tiff-4.0.9/libtiff/.libs/libtiff.a \
-I./tiff-4.0.9/libtiff \
-s EXPORTED_FUNCTIONS=”[‘_tiff_to_bmp’]” \
-s EXTRA_EXPORTED_RUNTIME_METHODS=”[‘ccall’, ‘cwrap’]” \
–pre-js LICENSE \
–pre-js tiff2bmpsw_pre.js \
–js-library tiff2bmpsw_jslib.js \
–post-js tiff2bmpsw_post.js \
-o tiff2bmpsw.js

注意加粗部分为改过的,红色部分为新加上去的不然运行报ccall没导出的错误

编完后把tiff2bmpsw.html、tiff2bmpsw.js、tiff2bmpsw.wasm放在web服务器上,就可以玩了