Actually piping the data through the compressor

This commit is contained in:
Surma
2018-05-17 22:27:24 +01:00
parent 8daaea5768
commit 49db0de05f
3 changed files with 48 additions and 6 deletions

View File

@@ -25,14 +25,28 @@ export default class App extends Component<Props, State> {
} }
} }
private async getImageData(bitmap: ImageBitmap): Promise<ImageData> {
// Make canvas same size as image
const canvas = document.createElement('canvas');
[canvas.width, canvas.height] = [bitmap.width, bitmap.height];
// Draw image onto canvas
const ctx = canvas.getContext('2d');
if (!ctx) {
throw new Error("Could not create canvas contex");
}
ctx.drawImage(bitmap, 0, 0);
return ctx.getImageData(0, 0, bitmap.width, bitmap.height);
}
@bind @bind
async onFileChange(event: Event) { async onFileChange(event: Event) {
const fileInput = event.target as HTMLInputElement; const fileInput = event.target as HTMLInputElement;
if (!fileInput.files || !fileInput.files[0]) return; if (!fileInput.files || !fileInput.files[0]) return;
// TODO: handle decode error // TODO: handle decode error
const img = await createImageBitmap(fileInput.files[0]); const bitmap = await createImageBitmap(fileInput.files[0]);
const data = await this.getImageData(bitmap);
const encoder = new MozJpegEncoder(); const encoder = new MozJpegEncoder();
const compressedData = await encoder.encode(img); const compressedData = await encoder.encode(data);
const blob = new Blob([compressedData], {type: 'image/jpeg'}); const blob = new Blob([compressedData], {type: 'image/jpeg'});
const compressedImage = await createImageBitmap(blob); const compressedImage = await createImageBitmap(blob);
this.setState({ img: compressedImage }); this.setState({ img: compressedImage });
@@ -53,3 +67,4 @@ export default class App extends Component<Props, State> {
); );
} }
} }

View File

@@ -1,5 +1,5 @@
export interface Encoder { export interface Encoder {
encode(image: ImageBitmap): Promise<ArrayBuffer>; encode(data: ImageData): Promise<ArrayBuffer | SharedArrayBuffer>;
} }
export interface Decoder { export interface Decoder {

View File

@@ -6,8 +6,10 @@ const wasmBinaryUrl = require('../../../codecs/mozjpeg_enc/mozjpeg_enc.wasm');
export class MozJpegEncoder implements Encoder { export class MozJpegEncoder implements Encoder {
private emscriptenModule: Promise<EmscriptenWasm.Module>; private emscriptenModule: Promise<EmscriptenWasm.Module>;
private api: any;
constructor() { constructor() {
this.emscriptenModule = new Promise(resolve => { this.emscriptenModule = new Promise(resolve => {
// TODO: See if I can just use m.then()?
const m = mozjpeg_enc({ const m = mozjpeg_enc({
// Just to be safe, dont automatically invoke any wasm functions // Just to be safe, dont automatically invoke any wasm functions
// noInitialRun: false, // noInitialRun: false,
@@ -25,11 +27,36 @@ export class MozJpegEncoder implements Encoder {
} }
}); });
}); });
this.api = (async () => {
// Not sure why, but TypeScript complains that I am using `emscriptenModule` before its getting assigned, which is clearly not true :shrug: Using `any`
const m = await (this as any).emscriptenModule;
return {
version: m.cwrap('version', 'number', []),
create_buffer: m.cwrap('create_buffer', 'number', ['number', 'number']),
destroy_buffer: m.cwrap('destroy_buffer', '', ['number']),
encode: m.cwrap('encode', '', ['number', 'number', 'number', 'number']),
free_result: m.cwrap('free_result', '', ['number']),
get_result_pointer: m.cwrap('get_result_pointer', 'number', []),
get_result_size: m.cwrap('get_result_size', 'number', []),
};
})();
} }
async encode(bitmap: ImageBitmap): Promise<ArrayBuffer> { async encode(data: ImageData): Promise<ArrayBuffer | SharedArrayBuffer> {
const m = await this.emscriptenModule; const m = await this.emscriptenModule;
console.log(m); const api = await this.api;
return Promise.resolve(<ArrayBuffer>new Uint8Array([1,2,3]).buffer);
const p = api.create_buffer(data.width, data.height);
m.HEAP8.set(data.data, p);
api.encode(p, data.width, data.height, 2);
const resultPointer = api.get_result_pointer();
const resultSize = api.get_result_size();
const resultView = new Uint8Array(m.HEAP8.buffer, resultPointer, resultSize);
const result = new Uint8Array(resultView);
api.free_result(resultPointer);
api.destroy_buffer(p);
return result.buffer;
} }
} }