forked from GoogleChromeLabs/squoosh
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request GoogleChromeLabs#35 from GoogleChromeLabs/load-codec
Load mozjpeg codec and encode image
- Loading branch information
Showing
9 changed files
with
274 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export default function(opts: EmscriptenWasm.ModuleOpts): EmscriptenWasm.Module; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
// These types roughly model the object that the JS files generated by Emscripten define. Copied from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/emscripten/index.d.ts and turned into a type definition rather than a global to support our way of using Emscripten. | ||
// TODO(@surma): Upstream this? | ||
declare namespace EmscriptenWasm { | ||
type EnvironmentType = "WEB" | "NODE" | "SHELL" | "WORKER"; | ||
|
||
// Options object for modularized Emscripten files. Shoe-horned by @surma. | ||
// FIXME: This an incomplete definition! | ||
interface ModuleOpts { | ||
noInitialRun?: boolean; | ||
locateFile?: (url: string) => string; | ||
onRuntimeInitialized?: () => void; | ||
} | ||
|
||
interface Module { | ||
print(str: string): void; | ||
printErr(str: string): void; | ||
arguments: string[]; | ||
environment: EnvironmentType; | ||
preInit: { (): void }[]; | ||
preRun: { (): void }[]; | ||
postRun: { (): void }[]; | ||
preinitializedWebGLContext: WebGLRenderingContext; | ||
noInitialRun: boolean; | ||
noExitRuntime: boolean; | ||
logReadFiles: boolean; | ||
filePackagePrefixURL: string; | ||
wasmBinary: ArrayBuffer; | ||
|
||
destroy(object: object): void; | ||
getPreloadedPackage(remotePackageName: string, remotePackageSize: number): ArrayBuffer; | ||
instantiateWasm( | ||
imports: WebAssembly.Imports, | ||
successCallback: (module: WebAssembly.Module) => void | ||
): WebAssembly.Exports; | ||
locateFile(url: string): string; | ||
onCustomMessage(event: MessageEvent): void; | ||
|
||
Runtime: any; | ||
|
||
ccall(ident: string, returnType: string | null, argTypes: string[], args: any[]): any; | ||
cwrap(ident: string, returnType: string | null, argTypes: string[]): any; | ||
|
||
setValue(ptr: number, value: any, type: string, noSafe?: boolean): void; | ||
getValue(ptr: number, type: string, noSafe?: boolean): number; | ||
|
||
ALLOC_NORMAL: number; | ||
ALLOC_STACK: number; | ||
ALLOC_STATIC: number; | ||
ALLOC_DYNAMIC: number; | ||
ALLOC_NONE: number; | ||
|
||
allocate(slab: any, types: string, allocator: number, ptr: number): number; | ||
allocate(slab: any, types: string[], allocator: number, ptr: number): number; | ||
|
||
Pointer_stringify(ptr: number, length?: number): string; | ||
UTF16ToString(ptr: number): string; | ||
stringToUTF16(str: string, outPtr: number): void; | ||
UTF32ToString(ptr: number): string; | ||
stringToUTF32(str: string, outPtr: number): void; | ||
|
||
// USE_TYPED_ARRAYS == 1 | ||
HEAP: Int32Array; | ||
IHEAP: Int32Array; | ||
FHEAP: Float64Array; | ||
|
||
// USE_TYPED_ARRAYS == 2 | ||
HEAP8: Int8Array; | ||
HEAP16: Int16Array; | ||
HEAP32: Int32Array; | ||
HEAPU8: Uint8Array; | ||
HEAPU16: Uint16Array; | ||
HEAPU32: Uint32Array; | ||
HEAPF32: Float32Array; | ||
HEAPF64: Float64Array; | ||
|
||
TOTAL_STACK: number; | ||
TOTAL_MEMORY: number; | ||
FAST_MEMORY: number; | ||
|
||
addOnPreRun(cb: () => any): void; | ||
addOnInit(cb: () => any): void; | ||
addOnPreMain(cb: () => any): void; | ||
addOnExit(cb: () => any): void; | ||
addOnPostRun(cb: () => any): void; | ||
|
||
// Tools | ||
intArrayFromString(stringy: string, dontAddNull?: boolean, length?: number): number[]; | ||
intArrayToString(array: number[]): string; | ||
writeStringToMemory(str: string, buffer: number, dontAddNull: boolean): void; | ||
writeArrayToMemory(array: number[], buffer: number): void; | ||
writeAsciiToMemory(str: string, buffer: number, dontAddNull: boolean): void; | ||
|
||
addRunDependency(id: any): void; | ||
removeRunDependency(id: any): void; | ||
|
||
|
||
preloadedImages: any; | ||
preloadedAudios: any; | ||
|
||
_malloc(size: number): number; | ||
_free(ptr: number): void; | ||
|
||
// Augmentations below by @surma. | ||
onRuntimeInitialized: () => void | null; | ||
} | ||
} | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export interface Encoder { | ||
encode(data: ImageData): Promise<ArrayBuffer>; | ||
} | ||
|
||
export interface Decoder { | ||
decode(data: ArrayBuffer): Promise<ImageBitmap>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import {Encoder} from './codec'; | ||
|
||
import mozjpeg_enc from '../../../codecs/mozjpeg_enc/mozjpeg_enc'; | ||
// Using require() so TypeScript doesn’t complain about this not being a module. | ||
const wasmBinaryUrl = require('../../../codecs/mozjpeg_enc/mozjpeg_enc.wasm'); | ||
|
||
// API exposed by wasm module. Details in the codec’s README. | ||
interface ModuleAPI { | ||
version(): number; | ||
create_buffer(width: number, height: number): number; | ||
destroy_buffer(pointer: number): void; | ||
encode(buffer: number, width: number, height: number, quality: number): void; | ||
free_result(): void; | ||
get_result_pointer(): number; | ||
get_result_size(): number; | ||
} | ||
|
||
export class MozJpegEncoder implements Encoder { | ||
private emscriptenModule: Promise<EmscriptenWasm.Module>; | ||
private api: Promise<ModuleAPI>; | ||
constructor() { | ||
this.emscriptenModule = new Promise(resolve => { | ||
const m = mozjpeg_enc({ | ||
// Just to be safe, don’t automatically invoke any wasm functions | ||
noInitialRun: false, | ||
locateFile(url: string): string { | ||
// Redirect the request for the wasm binary to whatever webpack gave us. | ||
if(url.endsWith('.wasm')) { | ||
return wasmBinaryUrl; | ||
} | ||
return url; | ||
}, | ||
onRuntimeInitialized() { | ||
// An Emscripten is a then-able that, for some reason, `then()`s itself, | ||
// causing an infite loop when you wrap it in a real promise. Deleten the `then` | ||
// prop solves this for now. | ||
// See: https://github.com/kripken/emscripten/blob/incoming/src/postamble.js#L129 | ||
// TODO(surma@): File a bug with Emscripten on this. | ||
delete (m as any).then; | ||
resolve(m); | ||
} | ||
}); | ||
}); | ||
|
||
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', '', []), | ||
get_result_pointer: m.cwrap('get_result_pointer', 'number', []), | ||
get_result_size: m.cwrap('get_result_size', 'number', []), | ||
}; | ||
})(); | ||
} | ||
|
||
async encode(data: ImageData): Promise<ArrayBuffer | SharedArrayBuffer> { | ||
const m = await this.emscriptenModule; | ||
const api = await this.api; | ||
|
||
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(); | ||
api.destroy_buffer(p); | ||
|
||
return result.buffer; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters