function StringToArrayBuffer(str) {
var buf = new ArrayBuffer(str.length);
var bufView = new Uint8Array(buf);
for (var i=0, strLen=str.length; i<strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
var HeifImage = function(handle) {
this.handle = handle;
this.img = null;
};
HeifImage.prototype.free = function() {
if (this.handle) {
libheif.heif_image_handle_release(this.handle);
this.handle = null;
}
};
HeifImage.prototype._ensureImage = function() {
if (this.img) {
return;
}
var img = libheif.heif_js_decode_image(this.handle,
libheif.heif_colorspace_YCbCr, libheif.heif_chroma_420);
if (!img || img.code) {
console.log("Decoding image failed", this.handle, img);
return;
}
this.data = new Uint8Array(StringToArrayBuffer(img.data));
delete img.data;
this.img = img;
};
HeifImage.prototype.get_width = function() {
this._ensureImage();
return this.img.width;
};
HeifImage.prototype.get_height = function() {
this._ensureImage();
return this.img.height;
};
HeifImage.prototype.is_primary = function() {
this._ensureImage();
return !!this.img.is_primary;
}
HeifImage.prototype.display = function(image_data, callback) {
// Defer color conversion.
var w = this.get_width();
var h = this.get_height();
setTimeout(function() {
this._ensureImage();
if (!this.img) {
// Decoding failed.
callback(null);
return;
}
var yval;
var uval;
var vval;
var xpos = 0;
var ypos = 0;
var w2 = w >> 1;
var maxi = w2*h;
var yoffset = 0;
var uoffset = 0;
var voffset = 0;
var x2;
var i2;
var y = this.data;
var u = this.data.subarray(w * h, w * h + (w * h / 4));
var v = this.data.subarray(w * h + (w * h / 4), w * h + (w * h / 2));
var stridey = w;
var strideu = w / 2;
var stridev = w / 2;
var dest = image_data.data;
for (var i=0; i<maxi; i++) {
i2 = i << 1;
x2 = (xpos << 1);
yval = 1.164 * (y[yoffset + x2] - 16);
uval = u[uoffset + xpos] - 128;
vval = v[voffset + xpos] - 128;
dest[(i2<<2)+0] = yval + 1.596 * vval;
dest[(i2<<2)+1] = yval - 0.813 * vval - 0.391 * uval;
dest[(i2<<2)+2] = yval + 2.018 * uval;
dest[(i2<<2)+3] = 0xff;
yval = 1.164 * (y[yoffset + x2 + 1] - 16);
dest[((i2+1)<<2)+0] = yval + 1.596 * vval;
dest[((i2+1)<<2)+1] = yval - 0.813 * vval - 0.391 * uval;
dest[((i2+1)<<2)+2] = yval + 2.018 * uval;
dest[((i2+1)<<2)+3] = 0xff;
xpos++;
if (xpos === w2) {
xpos = 0;
ypos++;
yoffset += stridey;
uoffset = ((ypos >> 1) * strideu);
voffset = ((ypos >> 1) * stridev);
}
}
callback(image_data);
}.bind(this), 0);
};
var HeifDecoder = function() {
this.decoder = null;
};
HeifDecoder.prototype.decode = function(buffer) {
if (this.decoder) {
libheif.heif_context_free(this.decoder);
}
this.decoder = libheif.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);
return [];
}
var ids = libheif.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) {
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]);
if (!handle || handle.code) {
console.log("Could not get image data for id", ids[i], handle);
continue;
}
result.push(new HeifImage(handle));
}
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);
}
};
var key;
// Expose enum values.
var enums = {
"heif_error_code": true,
"heif_suberror_code": true,
"heif_compression_format": true,
"heif_chroma": true,
"heif_colorspace": true,
"heif_channel": true
};
var e;
for (e in enums) {
if (!enums.hasOwnProperty(e)) {
continue;
}
for (key in Module[e]) {
if (!Module[e].hasOwnProperty(key) ||
key === "values") {
continue;
}
libheif[key] = Module[e][key];
}
}
// Expose internal C API.
for (key in Module) {
if (enums.hasOwnProperty(key) || key.indexOf("heif_") !== 0) {
continue;
}
libheif[key] = Module[key];
}
// 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 root = this;
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
/** @expose */
exports = module.exports = libheif;
}
/** @expose */
exports.libheif = libheif;
} else {
/** @expose */
root.libheif = libheif;
}
if (typeof define === "function" && define.amd) {
/** @expose */
define([], function() {
return libheif;
});
}
// NOTE: wrapped inside "(function() {" block from pre.js
}).call(this);