Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Emscripten CI and demo #1000

Merged
merged 3 commits into from
Oct 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/emscripten.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
jobs:
emscripten:
env:
EMSCRIPTEN_VERSION: 3.1.43
EMSCRIPTEN_VERSION: 3.1.47
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
Expand Down
23 changes: 12 additions & 11 deletions build-emscripten.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ if [ "$ENABLE_LIBDE265" = "1" ]; then
-L \
-o libde265-${LIBDE265_VERSION}.tar.gz \
https://github.com/strukturag/libde265/releases/download/v${LIBDE265_VERSION}/libde265-${LIBDE265_VERSION}.tar.gz
if [ ! -s "libde265-${LIBDE265_VERSION}/libde265/.libs/libde265.so" ]; then
if [ ! -s "libde265-${LIBDE265_VERSION}/libde265/.libs/libde265.a" ]; then
tar xf libde265-${LIBDE265_VERSION}.tar.gz
cd libde265-${LIBDE265_VERSION}
[ -x configure ] || ./autogen.sh
CXXFLAGS=-O3 emconfigure ./configure --disable-sse --disable-dec265 --disable-sherlock265
CXXFLAGS=-O3 emconfigure ./configure --enable-static --disable-shared --disable-sse --disable-dec265 --disable-sherlock265
emmake make -j${CORES}
cd ..
fi
Expand Down Expand Up @@ -72,7 +72,7 @@ if [ "$ENABLE_AOM" = "1" ]; then
-DENABLE_TOOLS=0 \
-DCONFIG_MULTITHREAD=0 \
-DCONFIG_RUNTIME_CPU_DETECT=0 \
-DBUILD_SHARED_LIBS=1 \
-DBUILD_SHARED_LIBS=0 \
-DCMAKE_BUILD_TYPE=Release

emmake make -j${CORES}
Expand All @@ -92,7 +92,7 @@ if [ "$STANDALONE" = "1" ]; then
EXTRA_COMPILER_FLAGS="-D__EMSCRIPTEN_STANDALONE_WASM__=1"
fi

CONFIGURE_ARGS="-DENABLE_MULTITHREADING_SUPPORT=OFF -DWITH_GDK_PIXBUF=OFF -DWITH_EXAMPLES=OFF -DBUILD_SHARED_LIBS=ON -DENABLE_PLUGIN_LOADING=OFF"
CONFIGURE_ARGS="-DENABLE_MULTITHREADING_SUPPORT=OFF -DWITH_GDK_PIXBUF=OFF -DWITH_EXAMPLES=OFF -DBUILD_SHARED_LIBS=OFF -DENABLE_PLUGIN_LOADING=OFF"
emcmake cmake ${SRCDIR} $CONFIGURE_ARGS \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_FLAGS="${EXTRA_COMPILER_FLAGS}" \
Expand All @@ -108,25 +108,26 @@ EXPORTED_FUNCTIONS=$($EMSDK/upstream/bin/llvm-nm $LIBHEIFA --format=just-symbols

echo "Running Emscripten..."

BUILD_FLAGS="-lembind -o libheif.js --pre-js ${SRCDIR}/pre.js --post-js ${SRCDIR}/post.js -sWASM=$USE_WASM"
BUILD_FLAGS="-lembind -o libheif.js --post-js ${SRCDIR}/post.js -sWASM=$USE_WASM"
RELEASE_BUILD_FLAGS="-O3"

if [ "$STANDALONE" = "1" ]; then
# Note: this intentionally overwrites the BUILD_FLAGS set above
echo "Building in standalone (non-web) build mode"
BUILD_FLAGS="-s STANDALONE_WASM=1 -s WASM=1 -o libheif.wasm --no-entry"
BUILD_FLAGS="-sSTANDALONE_WASM -sWASM -o libheif.wasm --no-entry"
fi

if [ "$DEBUG" = "1" ]; then
echo "Building in debug mode"
RELEASE_BUILD_FLAGS="--profile -g"
fi

emcc "$LIBHEIFA" \
-s EXPORTED_FUNCTIONS="$EXPORTED_FUNCTIONS,_free,_malloc,_memcpy" \
-s ALLOW_MEMORY_GROWTH=1 \
-s ERROR_ON_UNDEFINED_SYMBOLS=0 \
-s LLD_REPORT_UNDEFINED \
emcc -Wl,--whole-archive "$LIBHEIFA" -Wl,--no-whole-archive \
-sEXPORTED_FUNCTIONS="$EXPORTED_FUNCTIONS,_free,_malloc,_memcpy" \
-sMODULARIZE \
-sEXPORT_NAME="libheif" \
-sWASM_ASYNC_COMPILATION=0 \
-sALLOW_MEMORY_GROWTH \
--memory-init-file 0 \
-std=c++11 \
$LIBRARY_INCLUDE_FLAGS \
Expand Down
5 changes: 3 additions & 2 deletions examples/demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ <h1>libheif decoder demo</h1>
}.bind(this));
this.drawer = new CanvasDrawer(canvas);
this.decoder = new libheif.HeifDecoder();

console.log("Using libheif", libheif.heif_get_version());
saveSupported = this.canvas.toBlob &&
((URL && URL.createObjectURL) || navigator.msSaveOrOpenBlob);
if (saveSupported) {
Expand Down Expand Up @@ -313,8 +315,7 @@ <h1>libheif decoder demo</h1>
return;
}

console.log("Using libheif", libheif.heif_get_version());
var demo = new HeifDemo(libheif);
var demo = new HeifDemo(libheif());

show("form");

Expand Down
7 changes: 6 additions & 1 deletion libheif/heif_emscripten.h
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,12 @@ EMSCRIPTEN_BINDINGS(libheif) {
emscripten::class_<heif_image>("heif_image");
emscripten::value_object<heif_error>("heif_error")
.field("code", &heif_error::code)
.field("subcode", &heif_error::subcode);
.field("subcode", &heif_error::subcode)
.field("message", emscripten::optional_override([](const struct heif_error& err) {
return std::string(err.message);
}), emscripten::optional_override([](struct heif_error& err, const std::string& value) {
err.message = value.c_str();
}));
}

#endif // LIBHEIF_BOX_EMSCRIPTEN_H
126 changes: 51 additions & 75 deletions post.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var HeifImage = function(handle) {

HeifImage.prototype.free = function() {
if (this.handle) {
libheif.heif_image_handle_release(this.handle);
Module.heif_image_handle_release(this.handle);
this.handle = null;
}
};
Expand All @@ -24,8 +24,8 @@ HeifImage.prototype._ensureImage = function() {
return;
}

var img = libheif.heif_js_decode_image(this.handle,
libheif.heif_colorspace_YCbCr, libheif.heif_chroma_420);
var img = Module.heif_js_decode_image(this.handle,
Module.heif_colorspace.heif_colorspace_YCbCr, Module.heif_chroma.heif_chroma_420);
if (!img || img.code) {
console.log("Decoding image failed", this.handle, img);
return;
Expand All @@ -36,17 +36,17 @@ HeifImage.prototype._ensureImage = function() {
this.img = img;

if (img.alpha !== undefined) {
this.alpha = new Uint8Array(StringToArrayBuffer(img.alpha));
delete img.alpha;
this.alpha = new Uint8Array(StringToArrayBuffer(img.alpha));
delete img.alpha;
}
};

HeifImage.prototype.get_width = function() {
return libheif.heif_image_handle_get_width(this.handle);
return Module.heif_image_handle_get_width(this.handle);
};

HeifImage.prototype.get_height = function() {
return libheif.heif_image_handle_get_height(this.handle);
return Module.heif_image_handle_get_height(this.handle);
};

HeifImage.prototype.is_primary = function() {
Expand All @@ -63,8 +63,8 @@ HeifImage.prototype.display = function(image_data, callback) {
// If image hasn't been loaded yet, decode the image

if (!this.img) {
var img = libheif.heif_js_decode_image2(this.handle,
libheif.heif_colorspace_RGB, libheif.heif_chroma_interleaved_RGBA);
var img = Module.heif_js_decode_image2(this.handle,
Module.heif_colorspace.heif_colorspace_RGB, Module.heif_chroma.heif_chroma_interleaved_RGBA);
if (!img || img.code) {
console.log("Decoding image failed", this.handle, img);

Expand All @@ -73,14 +73,13 @@ HeifImage.prototype.display = function(image_data, callback) {
}

for (let c of img.channels) {
if (c.id == libheif.heif_channel_interleaved) {
if (c.id == Module.heif_channel.heif_channel_interleaved) {

// copy image into output array

if (c.stride == c.width*4) {
if (c.stride == c.width * 4) {
image_data.data.set(c.data);
}
else {
} else {
for (let y = 0; y < c.height; y++) {
let slice = c.data.slice(y * c.stride, y * c.stride + c.width * 4);
let offset = y * c.width * 4;
Expand All @@ -90,7 +89,7 @@ HeifImage.prototype.display = function(image_data, callback) {
}
}

libheif.heif_image_release(img.image);
Module.heif_image_release(img.image);
}

callback(image_data);
Expand All @@ -103,32 +102,31 @@ var HeifDecoder = function() {

HeifDecoder.prototype.decode = function(buffer) {
if (this.decoder) {
libheif.heif_context_free(this.decoder);
Module.heif_context_free(this.decoder);
}
this.decoder = libheif.heif_context_alloc();
this.decoder = Module.heif_context_alloc();
if (!this.decoder) {
console.log("Could not create HEIF context");
return [];
}
var error = libheif.heif_context_read_from_memory(this.decoder, buffer);
if (error.code !== libheif.heif_error_Ok) {
console.log("Could not parse HEIF file", error);
var error = Module.heif_context_read_from_memory(this.decoder, buffer);
if (error.code !== Module.heif_error_code.heif_error_Ok) {
console.log("Could not parse HEIF file", error.message);
return [];
}

var ids = libheif.heif_js_context_get_list_of_top_level_image_IDs(this.decoder);
var ids = Module.heif_js_context_get_list_of_top_level_image_IDs(this.decoder);
if (!ids || ids.code) {
console.log("Error loading image ids", ids);
return [];
}
else if (!ids.length) {
} else if (!ids.length) {
console.log("No images found");
return [];
}

var result = [];
for (var i = 0; i < ids.length; i++) {
var handle = libheif.heif_js_context_get_image_handle(this.decoder, ids[i]);
var handle = Module.heif_js_context_get_image_handle(this.decoder, ids[i]);
if (!handle || handle.code) {
console.log("Could not get image data for id", ids[i], handle);
continue;
Expand All @@ -139,61 +137,39 @@ HeifDecoder.prototype.decode = function(buffer) {
return result;
};

var libheif = {
// Expose high-level API.
/** @expose */
HeifDecoder: HeifDecoder,

// Expose low-level API.
/** @expose */
fourcc: function(s) {
return s.charCodeAt(0) << 24 |
s.charCodeAt(1) << 16 |
s.charCodeAt(2) << 8 |
s.charCodeAt(3);
}
};

// don't pollute the global namespace
delete this['Module'];

// On IE this function is called with "undefined" as first parameter. Override
// with a version that supports this behaviour.
function createNamedFunction(name, body) {
if (!name) {
name = "function_" + (new Date());
}
name = makeLegalFunctionName(name);
/*jshint evil:true*/
return new Function(
"body",
"return function " + name + "() {\n" +
" \"use strict\";" +
" return body.apply(this, arguments);\n" +
"};\n"
)(body);
var fourcc = function(s) {
return s.charCodeAt(0) << 24 |
s.charCodeAt(1) << 16 |
s.charCodeAt(2) << 8 |
s.charCodeAt(3);
}

var root = this;

if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
/** @expose */
exports = module.exports = libheif;
Module.HeifImage = HeifImage;
Module.HeifDecoder = HeifDecoder;
Module.fourcc = fourcc;

// Expose enum values.
const enums = [
'heif_error_code',
'heif_suberror_code',
'heif_compression_format',
'heif_chroma',
'heif_colorspace',
'heif_channel'
];
for (const e of enums) {
for (const key in Module[e]) {
if (!Module[e].hasOwnProperty(key) || key === 'values') {
continue;
}
Module[key] = Module[e][key];
}
/** @expose */
exports.libheif = libheif;
} else {
/** @expose */
root.libheif = libheif;
}

if (typeof define === "function" && define.amd) {
/** @expose */
define([], function() {
return libheif;
});
// Expose internal C API.
for (const key in Module) {
if (key.indexOf('_heif_') !== 0 || Module[key.slice(1)] !== undefined) {
continue;
}
Module[key.slice(1)] = Module[key];
}

// NOTE: wrapped inside "(function() {" block from pre.js
}).call(this);
75 changes: 0 additions & 75 deletions pre.js

This file was deleted.

Loading
Loading