mirror of
https://github.com/GoogleChromeLabs/squoosh.git
synced 2025-11-15 10:09:45 +00:00
Wrangling TypeScript and webpack to work with Emscripten wasm stuff
This commit is contained in:
1
codecs/mozjpeg_enc/mozjpeg_enc.d.ts
vendored
Normal file
1
codecs/mozjpeg_enc/mozjpeg_enc.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export default function(): EmscriptenWasm.Module;
|
||||||
99
emscripten-wasm.d.ts
vendored
Normal file
99
emscripten-wasm.d.ts
vendored
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
// 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";
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
24
package-lock.json
generated
24
package-lock.json
generated
@@ -385,6 +385,12 @@
|
|||||||
"integrity": "sha512-4Ba90mWNx8ddbafuyGGwjkZMigi+AWfYLSDCpovwsE63ia8w93r3oJ8PIAQc3y8U+XHcnMOHPIzNe3o438Ywcw==",
|
"integrity": "sha512-4Ba90mWNx8ddbafuyGGwjkZMigi+AWfYLSDCpovwsE63ia8w93r3oJ8PIAQc3y8U+XHcnMOHPIzNe3o438Ywcw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/webassembly-js-api": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/webassembly-js-api/-/webassembly-js-api-0.0.1.tgz",
|
||||||
|
"integrity": "sha1-YtULIBB319TMEJuxytoi/f1FI/s=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"abbrev": {
|
"abbrev": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||||
@@ -4529,6 +4535,24 @@
|
|||||||
"homedir-polyfill": "^1.0.1"
|
"homedir-polyfill": "^1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"exports-loader": {
|
||||||
|
"version": "0.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/exports-loader/-/exports-loader-0.7.0.tgz",
|
||||||
|
"integrity": "sha512-RKwCrO4A6IiKm0pG3c9V46JxIHcDplwwGJn6+JJ1RcVnh/WSGJa0xkmk5cRVtgOPzCAtTMGj2F7nluh9L0vpSA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"loader-utils": "^1.1.0",
|
||||||
|
"source-map": "0.5.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"source-map": {
|
||||||
|
"version": "0.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.0.tgz",
|
||||||
|
"integrity": "sha1-D+llA6yGpa213mP05BKuSHLNvoY=",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"express": {
|
"express": {
|
||||||
"version": "4.16.2",
|
"version": "4.16.2",
|
||||||
"resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz",
|
"resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz",
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"license": "apache-2.0",
|
"license": "apache-2.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"build:mozjpeg_enc": "cd codecs/mozjpeg_enc && npm run build",
|
||||||
|
"build:codecs": "npm run build:mozjpeg_enc",
|
||||||
"start": "webpack serve --hot",
|
"start": "webpack serve --hot",
|
||||||
"build": "webpack -p",
|
"build": "webpack -p",
|
||||||
"lint": "eslint src"
|
"lint": "eslint src"
|
||||||
@@ -30,6 +32,7 @@
|
|||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^9.4.7",
|
"@types/node": "^9.4.7",
|
||||||
|
"@types/webassembly-js-api": "0.0.1",
|
||||||
"babel-loader": "^7.1.4",
|
"babel-loader": "^7.1.4",
|
||||||
"babel-plugin-jsx-pragmatic": "^1.0.2",
|
"babel-plugin-jsx-pragmatic": "^1.0.2",
|
||||||
"babel-plugin-syntax-dynamic-import": "^6.18.0",
|
"babel-plugin-syntax-dynamic-import": "^6.18.0",
|
||||||
@@ -52,6 +55,7 @@
|
|||||||
"eslint-plugin-promise": "^3.7.0",
|
"eslint-plugin-promise": "^3.7.0",
|
||||||
"eslint-plugin-react": "^7.7.0",
|
"eslint-plugin-react": "^7.7.0",
|
||||||
"eslint-plugin-standard": "^3.0.1",
|
"eslint-plugin-standard": "^3.0.1",
|
||||||
|
"exports-loader": "^0.7.0",
|
||||||
"html-webpack-plugin": "^3.0.6",
|
"html-webpack-plugin": "^3.0.6",
|
||||||
"if-env": "^1.0.4",
|
"if-env": "^1.0.4",
|
||||||
"loader-utils": "^1.1.0",
|
"loader-utils": "^1.1.0",
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import { bind } from '../../lib/util';
|
|||||||
import * as style from './style.scss';
|
import * as style from './style.scss';
|
||||||
import Output from '../output';
|
import Output from '../output';
|
||||||
|
|
||||||
|
import {MozJpegEncoder} from '../../lib/codec-wrappers/mozjpeg-enc';
|
||||||
|
|
||||||
type Props = {};
|
type Props = {};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
@@ -29,7 +31,11 @@ export default class App extends Component<Props, State> {
|
|||||||
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 img = await createImageBitmap(fileInput.files[0]);
|
||||||
this.setState({ img });
|
const encoder = new MozJpegEncoder();
|
||||||
|
const compressedData = await encoder.encode(img);
|
||||||
|
const blob = new Blob([compressedData], {type: 'image/jpeg'});
|
||||||
|
const compressedImage = await createImageBitmap(blob);
|
||||||
|
this.setState({ img: compressedImage });
|
||||||
}
|
}
|
||||||
|
|
||||||
render({ }: Props, { img }: State) {
|
render({ }: Props, { img }: State) {
|
||||||
|
|||||||
7
src/lib/codec-wrappers/codec.ts
Normal file
7
src/lib/codec-wrappers/codec.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export interface Encoder {
|
||||||
|
encode(image: ImageBitmap): Promise<ArrayBuffer>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Decoder {
|
||||||
|
decode(data: ArrayBuffer): Promise<ImageBitmap>;
|
||||||
|
}
|
||||||
21
src/lib/codec-wrappers/mozjpeg-enc.ts
Normal file
21
src/lib/codec-wrappers/mozjpeg-enc.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import {Encoder} from './codec';
|
||||||
|
|
||||||
|
import mozjpeg_enc from '../../../codecs/mozjpeg_enc/mozjpeg_enc';
|
||||||
|
|
||||||
|
export class MozJpegEncoder implements Encoder {
|
||||||
|
private emscriptenModule: Promise<EmscriptenWasm.Module>;
|
||||||
|
constructor() {
|
||||||
|
this.emscriptenModule = new Promise(resolve => {
|
||||||
|
console.log(mozjpeg_enc);
|
||||||
|
const m = mozjpeg_enc();
|
||||||
|
m.onRuntimeInitialized = () => resolve(m);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async encode(bitmap: ImageBitmap): Promise<ArrayBuffer> {
|
||||||
|
console.log('encoding!');
|
||||||
|
const m = await this.emscriptenModule;
|
||||||
|
console.log(m);
|
||||||
|
return Promise.resolve(<ArrayBuffer>new Uint8Array([1,2,3]).buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -107,10 +107,17 @@ module.exports = function (_, env) {
|
|||||||
loader: 'babel-loader',
|
loader: 'babel-loader',
|
||||||
// Don't respect any Babel RC files found on the filesystem:
|
// Don't respect any Babel RC files found on the filesystem:
|
||||||
options: Object.assign(readJson('.babelrc'), { babelrc: false })
|
options: Object.assign(readJson('.babelrc'), { babelrc: false })
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// All the codec files define a global with the same name as their file name. `exports-loader` attaches those to `module.exports`.
|
||||||
|
test: /\/codec\/.*\.js$/,
|
||||||
|
loader: 'exports-loader',
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
// Ignore some of the native Node modules for any of the codecs. These files are generated by Emscripten and are supposed to also work in Node, which we don‘t care about.
|
||||||
|
new webpack.IgnorePlugin(/(fs)/, /\/codecs\//),
|
||||||
// Pretty progressbar showing build progress:
|
// Pretty progressbar showing build progress:
|
||||||
new ProgressBarPlugin({
|
new ProgressBarPlugin({
|
||||||
format: '\u001b[90m\u001b[44mBuild\u001b[49m\u001b[39m [:bar] \u001b[32m\u001b[1m:percent\u001b[22m\u001b[39m (:elapseds) \u001b[2m:msg\u001b[22m\r',
|
format: '\u001b[90m\u001b[44mBuild\u001b[49m\u001b[39m [:bar] \u001b[32m\u001b[1m:percent\u001b[22m\u001b[39m (:elapseds) \u001b[2m:msg\u001b[22m\r',
|
||||||
|
|||||||
Reference in New Issue
Block a user