fix(encoder): remove nested worker

Nested worker is not supported on safari
This commit is contained in:
wryk 2019-03-15 12:59:24 +01:00
parent 57d4a8dd52
commit 388a1f4bb5
4 changed files with 96 additions and 117 deletions

View file

@ -22,7 +22,7 @@ class OutputStream {
}
}
export function write (indexedColorImages, imageWidth, imageHeight, delay) {
export function write (imageWidth, imageHeight, delay, indexedColorImages) {
const emitter = new EventEmitter()
// yup, this is the browser nextTick implementation we are waiting for :facepalm:

View file

@ -1,42 +1,83 @@
import EventEmitter from 'eventemitter3'
import genericPool from 'generic-pool'
import pEvent from 'p-event'
import { write } from '/services/encode-core.js'
import { promisesProgress, calcProgress } from '/services/util.js'
const PALETTE_SIZE = 255
export function encode ({ imageDataList, imageWidth, imageHeight, delayTime }) {
const emitter = new EventEmitter()
const worker = new Worker('/services/encode.worker.js')
worker.onerror = error => emitter.emit('error', error)
worker.onmessageerror = error => emitter.emit('error', error)
worker.onmessage = event => {
const { type, payload } = event.data
switch (type) {
default:
emitter.emit('error', new Error(`Unexpected worker message with type ${type}`))
break
case 'progress':
emitter.emit('progress', payload.value)
break
case 'done':
const byteArray = new Uint8Array(payload.buffer)
const blob = new Blob([byteArray], { type: 'image/gif' })
const objectUrl = URL.createObjectURL(blob)
emitter.emit('done', objectUrl)
break
}
}
worker.postMessage({
imageDataList,
imageWidth,
imageHeight,
paletteSize: PALETTE_SIZE,
delayTime
const quantizeColorWorkerPool = genericPool.createPool({
create: () => new Worker('/services/quantize-color.worker.js'),
destroy: worker => worker.terminate()
}, {
min: 0,
max: 2
})
const indexedColorImagesP = imageDataList
.map(async imageData => {
const worker = await quantizeColorWorkerPool.acquire()
const indexedColorImage = await new Promise((resolve, reject) => {
worker.onerror = reject
worker.onmessageerror = reject
worker.onmessage = event => {
resolve(event.data)
}
worker.postMessage({
imageData,
paletteSize: PALETTE_SIZE
})
})
await quantizeColorWorkerPool.release(worker)
return indexedColorImage
})
const progressPromises = promisesProgress(indexedColorImagesP, function (value) {
emitter.emit('progress', calcProgress(0, 0.9, value))
})
Promise.all(progressPromises).then(indexedColorImages => {
const writeWorker = new Worker('/services/write-gif.worker.js')
writeWorker.onerror = error => emitter.emit('error', error)
writeWorker.onmessageerror = error => emitter.emit('error', error)
writeWorker.onmessage = event => {
const { type, payload } = event.data
switch (type) {
default:
emitter.emit('error', new Error(`Unexpected worker message with type ${type}`))
break
case 'progress':
emitter.emit('progress', calcProgress(0.9, 1, payload.value))
break
case 'done':
const byteArray = new Uint8Array(payload.buffer)
const blob = new Blob([byteArray], { type: 'image/gif' })
const objectUrl = URL.createObjectURL(blob)
emitter.emit('done', objectUrl)
break
}
}
writeWorker.postMessage({
imageWidth,
imageHeight,
indexedColorImages,
delayTime
})
})
.catch(error => emitter.emit('error', error))
return emitter
}

View file

@ -1,85 +0,0 @@
import genericPool from 'generic-pool'
import pEvent from 'p-event'
import { write } from '/services/encode-core.js'
import { promisesProgress, calcProgress } from '/services/util.js'
onmessage = handleMessage
const workerPool = genericPool.createPool({
create () {
return new Worker('/services/quantize-color.worker.js')
},
destroy (worker) {
worker.terminate()
}
}, {
min: 0,
max: 4
})
async function handleMessage (event) {
const { imageDataList, imageWidth, imageHeight, paletteSize, delayTime } = event.data
postProgressMessage(0)
console.time('quantization')
const promises = imageDataList
.map(async imageData => {
const worker = await workerPool.acquire()
const indexedColorImage = await new Promise((resolve, reject) => {
worker.onerror = reject
worker.onmessageerror = reject
worker.onmessage = event => {
resolve(event.data)
}
worker.postMessage({
imageData,
paletteSize
})
})
await workerPool.release(worker)
return indexedColorImage
})
const progressPromises = promisesProgress(promises, function (value) {
postProgressMessage(calcProgress(0, 0.9, value))
})
const indexedColorImages = await Promise.all(progressPromises)
console.timeEnd('quantization')
console.time('write')
const writing = write(indexedColorImages, imageWidth, imageHeight, delayTime)
writing.on('progress', value => postProgressMessage(calcProgress(0.9, 1, value)))
const buffer = await pEvent(writing, 'done')
console.timeEnd('write')
postDoneMessage(buffer)
}
function postProgressMessage (value) {
postMessage({
type: 'progress',
payload: {
value
}
})
}
function postDoneMessage (buffer) {
postMessage({
type: 'done',
payload: {
buffer
}
})
}

View file

@ -0,0 +1,23 @@
import { write } from '/services/encode-core.js'
onmessage = handleMessage
async function handleMessage (event) {
const { imageWidth, imageHeight, delayTime, indexedColorImages } = event.data
const writing = write(imageWidth, imageHeight, delayTime, indexedColorImages)
writing.on('progress', value => postMessage({
type: 'progress',
payload: {
value
}
}))
writing.once('done', buffer => postMessage({
type: 'done',
payload: {
buffer
}
}))
}