mirror of
https://github.com/GuerillaStudio/souvenir.git
synced 2024-11-08 12:11:53 +00:00
refact(workers): split encode-core
This commit is contained in:
parent
30a21b5709
commit
a2017f3f47
5 changed files with 89 additions and 108 deletions
|
@ -1,84 +0,0 @@
|
|||
import EventEmitter from 'eventemitter3'
|
||||
|
||||
import {
|
||||
GifWriter,
|
||||
MedianCutColorReducer,
|
||||
IndexedColorImage
|
||||
} from 'gif-writer'
|
||||
|
||||
import { boomerang } from '/services/effects.js'
|
||||
import { pipe, calcProgress } from '/services/util.js'
|
||||
|
||||
class OutputStream {
|
||||
constructor () {
|
||||
this.buffer = []
|
||||
}
|
||||
|
||||
writeByte (b) {
|
||||
this.buffer.push(b)
|
||||
}
|
||||
|
||||
writeBytes (bb) {
|
||||
Array.prototype.push.apply(this.buffer, bb)
|
||||
}
|
||||
}
|
||||
|
||||
export function write (imageWidth, imageHeight, delay, indexedColorImages, boomerangEffect = false) {
|
||||
const emitter = new EventEmitter()
|
||||
|
||||
// yup, this is the browser nextTick implementation we are waiting for :facepalm:
|
||||
Promise.resolve().then(() => {
|
||||
emitter.emit('progress', 0)
|
||||
|
||||
const outputStream = new OutputStream()
|
||||
const writer = new GifWriter(outputStream)
|
||||
|
||||
writer.writeHeader()
|
||||
|
||||
writer.writeLogicalScreenInfo({
|
||||
width: imageWidth,
|
||||
height: imageHeight
|
||||
})
|
||||
|
||||
writer.writeLoopControlInfo(0)
|
||||
|
||||
const frames = pipe(indexedColorImages, [
|
||||
(images) => boomerangEffect ? boomerang(images) : images
|
||||
])
|
||||
|
||||
frames.forEach((indexedColorImage, index, { length }) => {
|
||||
writer.writeTableBasedImageWithGraphicControl(indexedColorImage, { delayTimeInMS: delay })
|
||||
emitter.emit('progress', calcProgress(0, 0.99, (index + 1) / length))
|
||||
})
|
||||
|
||||
writer.writeTrailer()
|
||||
emitter.emit('progress', 1)
|
||||
|
||||
emitter.emit('done', outputStream.buffer)
|
||||
})
|
||||
|
||||
return emitter
|
||||
}
|
||||
|
||||
export function convertImageDataToIndexedColorImage (imageData, paletteSize) {
|
||||
const reducer = new MedianCutColorReducer(imageData, paletteSize)
|
||||
|
||||
const paletteData = reducer.process()
|
||||
|
||||
const data = Array.from(imageData.data)
|
||||
const indexedColorImageData = []
|
||||
|
||||
for (let index = 0, length = data.length; index < length; index += 4) {
|
||||
const [r, g, b] = data.slice(index, index + 4) // r,g,b,a
|
||||
indexedColorImageData.push(reducer.map(r, g, b))
|
||||
}
|
||||
|
||||
return new IndexedColorImage(
|
||||
{
|
||||
width: imageData.width,
|
||||
height: imageData.height
|
||||
},
|
||||
indexedColorImageData,
|
||||
paletteData
|
||||
)
|
||||
}
|
27
src/services/quantize-color.js
Normal file
27
src/services/quantize-color.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
import {
|
||||
MedianCutColorReducer,
|
||||
IndexedColorImage
|
||||
} from 'gif-writer'
|
||||
|
||||
export function convertImageDataToIndexedColorImage (imageData, paletteSize) {
|
||||
const reducer = new MedianCutColorReducer(imageData, paletteSize)
|
||||
|
||||
const paletteData = reducer.process()
|
||||
|
||||
const data = Array.from(imageData.data)
|
||||
const indexedColorImageData = []
|
||||
|
||||
for (let index = 0, length = data.length; index < length; index += 4) {
|
||||
const [r, g, b] = data.slice(index, index + 4) // r,g,b,a
|
||||
indexedColorImageData.push(reducer.map(r, g, b))
|
||||
}
|
||||
|
||||
return new IndexedColorImage(
|
||||
{
|
||||
width: imageData.width,
|
||||
height: imageData.height
|
||||
},
|
||||
indexedColorImageData,
|
||||
paletteData
|
||||
)
|
||||
}
|
|
@ -1,11 +1,7 @@
|
|||
import { convertImageDataToIndexedColorImage } from '/services/encode-core.js'
|
||||
import { convertImageDataToIndexedColorImage } from '/services/quantize-color.js'
|
||||
|
||||
onmessage = handleMessage
|
||||
|
||||
function handleMessage (event) {
|
||||
onmessage = event => {
|
||||
const { imageData, paletteSize } = event.data
|
||||
|
||||
const indexedColorImage = convertImageDataToIndexedColorImage(imageData, paletteSize)
|
||||
|
||||
postMessage(indexedColorImage)
|
||||
postMessage(convertImageDataToIndexedColorImage(imageData, paletteSize))
|
||||
}
|
||||
|
|
46
src/services/write-gif.js
Normal file
46
src/services/write-gif.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
import { GifWriter } from 'gif-writer'
|
||||
import { boomerang } from '/services/effects.js'
|
||||
import { pipe, calcProgress } from '/services/util.js'
|
||||
|
||||
class OutputStream {
|
||||
constructor () {
|
||||
this.buffer = []
|
||||
}
|
||||
|
||||
writeByte (b) {
|
||||
this.buffer.push(b)
|
||||
}
|
||||
|
||||
writeBytes (bb) {
|
||||
Array.prototype.push.apply(this.buffer, bb)
|
||||
}
|
||||
}
|
||||
|
||||
export function write (imageWidth, imageHeight, delay, indexedColorImages, boomerangEffect, progressCallback) {
|
||||
const outputStream = new OutputStream()
|
||||
const writer = new GifWriter(outputStream)
|
||||
|
||||
progressCallback(0)
|
||||
writer.writeHeader()
|
||||
|
||||
writer.writeLogicalScreenInfo({
|
||||
width: imageWidth,
|
||||
height: imageHeight
|
||||
})
|
||||
|
||||
writer.writeLoopControlInfo(0)
|
||||
|
||||
const frames = pipe(indexedColorImages, [
|
||||
(images) => boomerangEffect ? boomerang(images) : images
|
||||
])
|
||||
|
||||
frames.forEach((indexedColorImage, index, { length }) => {
|
||||
writer.writeTableBasedImageWithGraphicControl(indexedColorImage, { delayTimeInMS: delay })
|
||||
progressCallback(calcProgress(0, 0.99, (index + 1) / length))
|
||||
})
|
||||
|
||||
writer.writeTrailer()
|
||||
progressCallback(1)
|
||||
|
||||
return outputStream.buffer
|
||||
}
|
|
@ -1,23 +1,19 @@
|
|||
import { write } from '/services/encode-core.js'
|
||||
import { write } from '/services/write-gif.js'
|
||||
|
||||
onmessage = handleMessage
|
||||
const postProgressMessage = value => postMessage({ type: 'progress', payload: { value } })
|
||||
const postDoneMessage = buffer => postMessage({ type: 'done', payload: { buffer } })
|
||||
|
||||
async function handleMessage (event) {
|
||||
onmessage = event => {
|
||||
const { imageWidth, imageHeight, delayTime, indexedColorImages, boomerangEffect } = event.data
|
||||
|
||||
const writing = write(imageWidth, imageHeight, delayTime, indexedColorImages, boomerangEffect)
|
||||
const buffer = write(
|
||||
imageWidth,
|
||||
imageHeight,
|
||||
delayTime,
|
||||
indexedColorImages,
|
||||
boomerangEffect,
|
||||
postProgressMessage
|
||||
)
|
||||
|
||||
writing.on('progress', value => postMessage({
|
||||
type: 'progress',
|
||||
payload: {
|
||||
value
|
||||
}
|
||||
}))
|
||||
|
||||
writing.once('done', buffer => postMessage({
|
||||
type: 'done',
|
||||
payload: {
|
||||
buffer
|
||||
}
|
||||
}))
|
||||
postDoneMessage(buffer)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue