post.js (142 lines of code) (raw):
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) {
Module.heif_image_handle_release(this.handle);
this.handle = null;
}
};
HeifImage.prototype._ensureImage = function() {
if (this.img) {
return;
}
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;
}
this.data = new Uint8Array(StringToArrayBuffer(img.data));
delete img.data;
this.img = img;
if (img.alpha !== undefined) {
this.alpha = new Uint8Array(StringToArrayBuffer(img.alpha));
delete img.alpha;
}
};
HeifImage.prototype.get_width = function() {
return Module.heif_image_handle_get_width(this.handle);
};
HeifImage.prototype.get_height = function() {
return Module.heif_image_handle_get_height(this.handle);
};
HeifImage.prototype.is_primary = function() {
return !!heif_image_handle_is_primary_image(this.handle);
}
HeifImage.prototype.display = function(image_data, callback) {
// Defer color conversion.
var w = this.get_width();
var h = this.get_height();
setTimeout(function() {
// If image hasn't been loaded yet, decode the image
if (!this.img) {
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);
callback(null);
return;
}
for (let c of img.channels) {
if (c.id == Module.heif_channel.heif_channel_interleaved) {
// copy image into output array
if (c.stride == c.width * 4) {
image_data.data.set(c.data);
} 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;
image_data.data.set(slice, offset);
}
}
}
}
Module.heif_image_release(img.image);
}
callback(image_data);
}.bind(this), 0);
};
var HeifDecoder = function() {
this.decoder = null;
};
HeifDecoder.prototype.decode = function(buffer) {
if (this.decoder) {
Module.heif_context_free(this.decoder);
}
this.decoder = Module.heif_context_alloc();
if (!this.decoder) {
console.log("Could not create HEIF context");
return [];
}
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 = 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) {
console.log("No images found");
return [];
}
var result = [];
for (var i = 0; i < ids.length; 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;
}
result.push(new HeifImage(handle));
}
return result;
};
var fourcc = function(s) {
return s.charCodeAt(0) << 24 |
s.charCodeAt(1) << 16 |
s.charCodeAt(2) << 8 |
s.charCodeAt(3);
}
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 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];
}