mirror of
https://github.com/GuerillaStudio/souvenir.git
synced 2025-01-20 18:50:21 +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
|
onmessage = event => {
|
||||||
|
|
||||||
function handleMessage (event) {
|
|
||||||
const { imageData, paletteSize } = event.data
|
const { imageData, paletteSize } = event.data
|
||||||
|
|
||||||
const indexedColorImage = convertImageDataToIndexedColorImage(imageData, paletteSize)
|
postMessage(convertImageDataToIndexedColorImage(imageData, paletteSize))
|
||||||
|
|
||||||
postMessage(indexedColorImage)
|
|
||||||
}
|
}
|
||||||
|
|
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 { 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({
|
postDoneMessage(buffer)
|
||||||
type: 'progress',
|
|
||||||
payload: {
|
|
||||||
value
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
|
|
||||||
writing.once('done', buffer => postMessage({
|
|
||||||
type: 'done',
|
|
||||||
payload: {
|
|
||||||
buffer
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue