mirror of
https://github.com/GoogleChromeLabs/squoosh.git
synced 2025-11-14 17:49:52 +00:00
Actually piping the data through the compressor
This commit is contained in:
@@ -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> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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, don’t automatically invoke any wasm functions
|
// Just to be safe, don’t 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 it’s 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user