mirror of
https://github.com/john-okeefe/foliate-js.git
synced 2026-09-09 11:29:14 -04:00
Speed up text sectioning for large MOBI books (#92)
This commit is contained in:
@@ -658,6 +658,15 @@ const getIndent = el => {
|
||||
return x
|
||||
}
|
||||
|
||||
function rawBytesToString(uint8Array) {
|
||||
const chunkSize = 0x8000
|
||||
let result = ''
|
||||
for (let i = 0; i < uint8Array.length; i += chunkSize) {
|
||||
result += String.fromCharCode.apply(null, uint8Array.subarray(i, i + chunkSize))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
class MOBI6 {
|
||||
parser = new DOMParser()
|
||||
serializer = new XMLSerializer()
|
||||
@@ -671,32 +680,37 @@ class MOBI6 {
|
||||
this.mobi = mobi
|
||||
}
|
||||
async init() {
|
||||
const recordBuffers = []
|
||||
for (let i = 0; i < this.mobi.headers.palmdoc.numTextRecords; i++) {
|
||||
const buf = await this.mobi.loadText(i)
|
||||
recordBuffers.push(buf)
|
||||
}
|
||||
const totalLength = recordBuffers.reduce((sum, buf) => sum + buf.byteLength, 0)
|
||||
// load all text records in an array
|
||||
let array = new Uint8Array()
|
||||
for (let i = 0; i < this.mobi.headers.palmdoc.numTextRecords; i++)
|
||||
array = concatTypedArray(array, await this.mobi.loadText(i))
|
||||
|
||||
const array = new Uint8Array(totalLength)
|
||||
recordBuffers.reduce((offset, buf) => {
|
||||
array.set(new Uint8Array(buf), offset)
|
||||
return offset + buf.byteLength
|
||||
}, 0)
|
||||
// convert to string so we can use regex
|
||||
// note that `filepos` are byte offsets
|
||||
// so it needs to preserve each byte as a separate character
|
||||
// (see https://stackoverflow.com/q/50198017)
|
||||
const str = Array.from(new Uint8Array(array),
|
||||
c => String.fromCharCode(c)).join('')
|
||||
const str = rawBytesToString(array)
|
||||
|
||||
// split content into sections at each `<mbp:pagebreak>`
|
||||
this.#sections = [0]
|
||||
.concat(Array.from(str.matchAll(mbpPagebreakRegex), m => m.index))
|
||||
.map((x, i, a) => str.slice(x, a[i + 1]))
|
||||
// recover the original raw bytes
|
||||
.map(str => Uint8Array.from(str, x => x.charCodeAt(0)))
|
||||
.map(raw => ({ book: this, raw }))
|
||||
.map((start, i, a) => {
|
||||
const end = a[i + 1] ?? array.length
|
||||
return { book: this, raw: array.subarray(start, end) }
|
||||
})
|
||||
// get start and end filepos for each section
|
||||
.reduce((arr, x) => {
|
||||
const last = arr[arr.length - 1]
|
||||
x.start = last?.end ?? 0
|
||||
x.end = x.start + x.raw.byteLength
|
||||
return arr.concat(x)
|
||||
}, [])
|
||||
.map((section, i, arr) => {
|
||||
section.start = arr[i - 1]?.end ?? 0
|
||||
section.end = section.start + section.raw.byteLength
|
||||
return section
|
||||
})
|
||||
|
||||
this.sections = this.#sections.map((section, index) => ({
|
||||
id: index,
|
||||
|
||||
Reference in New Issue
Block a user