2021-06-23 23:31:12 +08:00
function resizeWithAspect (
input _width ,
input _height ,
target _width ,
target _height ,
) {
if ( ! target _width && ! target _height ) {
throw Error ( 'Need to specify at least width or height when resizing' ) ;
}
if ( target _width && target _height ) {
return { width : target _width , height : target _height } ;
}
if ( ! target _width ) {
return {
width : Math . round ( ( input _width / input _height ) * target _height ) ,
height : target _height ,
} ;
}
return {
width : target _width ,
height : Math . round ( ( input _height / input _width ) * target _width ) ,
} ;
}
function logIfDebug ( message ) {
if ( DedicatedWorkerGlobalScope . debugMode ) {
// eslint-disable-next-line no-console
console . log ( message ) ;
}
}
async function optimize ( imageData , fileName , width , height , settings ) {
await loadLibs ( settings ) ;
const mozJpegDefaultOptions = {
quality : settings . encode _quality ,
baseline : false ,
arithmetic : false ,
progressive : true ,
optimize _coding : true ,
smoothing : 0 ,
color _space : 3 /*YCbCr*/ ,
quant _table : 3 ,
trellis _multipass : false ,
trellis _opt _zero : false ,
trellis _opt _table : false ,
trellis _loops : 1 ,
auto _subsample : true ,
chroma _subsample : 2 ,
separate _chroma _quality : false ,
chroma _quality : 75 ,
} ;
const initialSize = imageData . byteLength ;
logIfDebug ( ` Worker received imageData: ${ initialSize } ` ) ;
let maybeResized ;
// resize
if ( width > settings . resize _threshold ) {
try {
const target _dimensions = resizeWithAspect ( width , height , settings . resize _target ) ;
const resizeResult = self . codecs . resize (
new Uint8ClampedArray ( imageData ) ,
width , //in
height , //in
target _dimensions . width , //out
target _dimensions . height , //out
3 , // 3 is lanczos
settings . resize _pre _multiply ,
settings . resize _linear _rgb
) ;
2021-07-01 03:01:17 +08:00
if ( resizeResult [ 3 ] !== 255 ) {
throw "Image corrupted during resize. Falling back to the original for encode"
}
2021-06-23 23:31:12 +08:00
maybeResized = new ImageData (
resizeResult ,
target _dimensions . width ,
target _dimensions . height ,
) . data ;
width = target _dimensions . width ;
height = target _dimensions . height ;
2021-06-29 05:21:39 +08:00
logIfDebug ( ` Worker post resizing file: ${ maybeResized . byteLength } ` ) ;
2021-06-23 23:31:12 +08:00
} catch ( error ) {
console . error ( ` Resize failed: ${ error } ` ) ;
maybeResized = imageData ;
}
} else {
logIfDebug ( ` Skipped resize: ${ width } < ${ settings . resize _threshold } ` ) ;
maybeResized = imageData ;
}
// mozJPEG re-encode
const result = self . codecs . mozjpeg _enc . encode (
maybeResized ,
width ,
height ,
mozJpegDefaultOptions
) ;
const finalSize = result . byteLength
logIfDebug ( ` Worker post reencode file: ${ finalSize } ` ) ;
logIfDebug ( ` Reduction: ${ ( initialSize / finalSize ) . toFixed ( 1 ) } x speedup ` ) ;
2021-07-01 03:01:17 +08:00
if ( finalSize < 20000 ) {
throw "Final size suspciously small, discarding optimizations"
}
2021-06-23 23:31:12 +08:00
let transferrable = Uint8Array . from ( result ) . buffer ; // decoded was allocated inside WASM so it **cannot** be transfered to another context, need to copy by value
return transferrable ;
}
onmessage = async function ( e ) {
switch ( e . data . type ) {
case "compress" :
try {
DedicatedWorkerGlobalScope . debugMode = e . data . settings . debug _mode ;
let optimized = await optimize (
e . data . file ,
e . data . fileName ,
e . data . width ,
e . data . height ,
e . data . settings
) ;
postMessage (
{
type : "file" ,
file : optimized ,
fileName : e . data . fileName
} ,
[ optimized ]
) ;
} catch ( error ) {
console . error ( error ) ;
postMessage ( {
type : "error" ,
FEATURE: First pass of using uppy in the composer (#13935)
Adds uppy upload functionality behind a
enable_experimental_composer_uploader site setting (default false,
and hidden).
When enabled this site setting will make the composer-editor-uppy
component be used within composer.hbs, which in turn points to
a ComposerUploadUppy mixin which overrides the relevant
functions from ComposerUpload. This uppy uploader has parity
with all the features of jQuery file uploader in the original
composer-editor, including:
progress tracking
error handling
number of files validation
pasting files
dragging and dropping files
updating upload placeholders
upload markdown resolvers
processing actions (the only one we have so far is the media optimization
worker by falco, this works)
cancelling uploads
For now all uploads still go via the /uploads.json endpoint, direct
S3 support will be added later.
Also included in this PR are some changes to the media optimization
service, to support uppy's different file data structures, and also
to make the promise tracking and resolving more robust. Currently
it uses the file name to track promises, we can switch to something
more unique later if needed.
Does not include custom upload handlers, that will come
in a later PR, it is a tricky problem to handle.
Also, this new functionality will not be used in encrypted PMs because
encrypted PM uploads rely on custom upload handlers.
2021-08-13 07:14:34 +08:00
file : e . data . file
2021-06-23 23:31:12 +08:00
} ) ;
}
break ;
default :
logIfDebug ( ` Sorry, we are out of ${ e } . ` ) ;
}
} ;
async function loadLibs ( settings ) {
if ( self . codecs ) return ;
importScripts ( settings . mozjpeg _script ) ;
importScripts ( settings . resize _script ) ;
let encoderModuleOverrides = {
locateFile : function ( path , prefix ) {
// if it's a mem init file, use a custom dir
if ( path . endsWith ( ".wasm" ) ) return settings . mozjpeg _wasm ;
// otherwise, use the default, the prefix (JS file's dir) + the path
return prefix + path ;
} ,
onRuntimeInitialized : function ( ) {
return this ;
} ,
} ;
const mozjpeg _enc _module = await mozjpeg _enc ( encoderModuleOverrides ) ;
const { resize } = wasm _bindgen ;
await wasm _bindgen ( settings . resize _wasm ) ;
self . codecs = { mozjpeg _enc : mozjpeg _enc _module , resize : resize } ;
}