Transpile libimagequant

This commit is contained in:
Surma
2018-07-30 15:49:38 +01:00
parent f2f467ecb8
commit 9d5ad83ff8
8 changed files with 1333 additions and 0 deletions

View File

@ -0,0 +1,38 @@
# ImageQuant
- Source: <https://github.com/ImageOptim/libimagequant>
- Version: v2.12.1
## Dependencies
- Docker
## Example
See `example.html`
## API
### `int version()`
Returns the version of libimagequant as a number. va.b.c is encoded as 0x0a0b0c
### `uint8_t* create_buffer(int width, int height)`
Allocates an RGBA buffer for an image with the given dimension.
### `void destroy_buffer(uint8_t* p)`
Frees a buffer created with `create_buffer`.
### `void quantize(uint8_t* image_buffer, int image_width, int image_height, int numColors, float dithering)`
Quantizes the given images, using at most `numColors`, a value between 2 and 256. `dithering` is a value between 0 and 1 controlling the amount of dithering.
### `void free_result()`
Frees the result created by `encode()`.
### `int get_result_pointer()`
Returns the pointer to the start of the buffer holding the encoded data. It has the same size as the input image buffer.

View File

@ -0,0 +1,49 @@
<!doctype html>
<script src='imagequant.js'></script>
<script>
const Module = imagequant();
async function loadImage(src) {
// Load image
const img = document.createElement('img');
img.src = src;
await new Promise(resolve => img.onload = resolve);
// Make canvas same size as image
const canvas = document.createElement('canvas');
[canvas.width, canvas.height] = [img.width, img.height];
// Draw image onto canvas
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
return ctx.getImageData(0, 0, img.width, img.height);
}
Module.onRuntimeInitialized = async _ => {
const api = {
version: Module.cwrap('version', 'number', []),
create_buffer: Module.cwrap('create_buffer', 'number', ['number', 'number']),
destroy_buffer: Module.cwrap('destroy_buffer', '', ['number']),
quantize: Module.cwrap('quantize', '', ['number', 'number', 'number', 'number', 'number']),
free_result: Module.cwrap('free_result', '', ['number']),
get_result_pointer: Module.cwrap('get_result_pointer', 'number', []),
// get_result_size: Module.cwrap('get_result_size', 'number', []),
};
console.log('Version:', api.version().toString(16));
const image = await loadImage('../example.png');
const p = api.create_buffer(image.width, image.height);
Module.HEAP8.set(image.data, p);
api.quantize(p, image.width, image.height, 16, 1.0);
const resultPointer = api.get_result_pointer();
const resultView = new Uint8Array(Module.HEAP8.buffer, resultPointer, image.width * image.height * 4);
const result = new Uint8ClampedArray(resultView);
api.free_result();
api.destroy_buffer(p);
const imageData = new ImageData(result, image.width, image.height);
const canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
const ctx = canvas.getContext('2d');
ctx.putImageData(imageData, 0, 0);
document.body.appendChild(canvas);
};
</script>

View File

@ -0,0 +1,67 @@
#include "emscripten.h"
#include <stdlib.h>
#include <inttypes.h>
#include "libimagequant.h"
EMSCRIPTEN_KEEPALIVE
int version() {
return (((LIQ_VERSION/10000) % 100) << 16) |
(((LIQ_VERSION/100 ) % 100) << 8) |
(((LIQ_VERSION/1 ) % 100) << 0);
}
EMSCRIPTEN_KEEPALIVE
uint8_t* create_buffer(int width, int height) {
return malloc(width * height * 4 * sizeof(uint8_t));
}
EMSCRIPTEN_KEEPALIVE
void destroy_buffer(uint8_t* p) {
free(p);
}
liq_attr *attr;
liq_image *image;
liq_result *res;
int result[2];
EMSCRIPTEN_KEEPALIVE
void quantize(uint8_t* image_buffer, int image_width, int image_height, int num_colors, float dithering) {
int size = image_width * image_height;
attr = liq_attr_create();
image = liq_image_create_rgba(attr, image_buffer, image_width, image_height, 0);
liq_set_max_colors(attr, 16);
liq_image_quantize(image, attr, &res);
liq_set_dithering_level(res, dithering);
uint8_t* image8bit = (uint8_t*) malloc(size);
result[0] = (int) malloc(size * 4);
liq_write_remapped_image(res, image, image8bit, size);
const liq_palette *pal = liq_get_palette(res);
// Turn palletted image back into an RGBA image
for(int i = 0; i < size; i++) {
((uint8_t*)result[0])[i * 4 + 0] = pal->entries[image8bit[i]].r;
((uint8_t*)result[0])[i * 4 + 1] = pal->entries[image8bit[i]].g;
((uint8_t*)result[0])[i * 4 + 2] = pal->entries[image8bit[i]].b;
((uint8_t*)result[0])[i * 4 + 3] = pal->entries[image8bit[i]].a;
}
free(image8bit);
liq_result_destroy(res);
liq_image_destroy(image);
liq_attr_destroy(attr);
}
EMSCRIPTEN_KEEPALIVE
void free_result() {
free(result[0]);
}
EMSCRIPTEN_KEEPALIVE
int get_result_pointer() {
return result[0];
}
EMSCRIPTEN_KEEPALIVE
int get_result_palette_pointer() {
return result[1];
}

1
codecs/imagequant/imagequant.d.ts vendored Normal file
View File

@ -0,0 +1 @@
export default function(opts: EmscriptenWasm.ModuleOpts): EmscriptenWasm.Module;

File diff suppressed because one or more lines are too long

Binary file not shown.

1147
codecs/imagequant/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
{
"name": "imagequant",
"scripts": {
"install": "napa",
"build": "npm run build:wasm",
"build:wasm": "docker run --rm -v $(pwd):/src trzeci/emscripten emcc -O3 -s WASM=1 -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"cwrap\"]' -s ALLOW_MEMORY_GROWTH=1 -s MODULARIZE=1 -s 'EXPORT_NAME=\"imagequant\"' -I node_modules/libimagequant -o ./imagequant.js imagequant.c node_modules/libimagequant/{libimagequant,pam,mediancut,blur,mempool,kmeans,nearest}.c"
},
"napa": {
"libimagequant": "ImageOptim/libimagequant#2.12.1"
},
"devDependencies": {
"napa": "^3.0.0"
}
}