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
|
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 {
|
class MOBI6 {
|
||||||
parser = new DOMParser()
|
parser = new DOMParser()
|
||||||
serializer = new XMLSerializer()
|
serializer = new XMLSerializer()
|
||||||
@@ -671,32 +680,37 @@ class MOBI6 {
|
|||||||
this.mobi = mobi
|
this.mobi = mobi
|
||||||
}
|
}
|
||||||
async init() {
|
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
|
// load all text records in an array
|
||||||
let array = new Uint8Array()
|
const array = new Uint8Array(totalLength)
|
||||||
for (let i = 0; i < this.mobi.headers.palmdoc.numTextRecords; i++)
|
recordBuffers.reduce((offset, buf) => {
|
||||||
array = concatTypedArray(array, await this.mobi.loadText(i))
|
array.set(new Uint8Array(buf), offset)
|
||||||
|
return offset + buf.byteLength
|
||||||
|
}, 0)
|
||||||
// convert to string so we can use regex
|
// convert to string so we can use regex
|
||||||
// note that `filepos` are byte offsets
|
// note that `filepos` are byte offsets
|
||||||
// so it needs to preserve each byte as a separate character
|
// so it needs to preserve each byte as a separate character
|
||||||
// (see https://stackoverflow.com/q/50198017)
|
// (see https://stackoverflow.com/q/50198017)
|
||||||
const str = Array.from(new Uint8Array(array),
|
const str = rawBytesToString(array)
|
||||||
c => String.fromCharCode(c)).join('')
|
|
||||||
|
|
||||||
// split content into sections at each `<mbp:pagebreak>`
|
// split content into sections at each `<mbp:pagebreak>`
|
||||||
this.#sections = [0]
|
this.#sections = [0]
|
||||||
.concat(Array.from(str.matchAll(mbpPagebreakRegex), m => m.index))
|
.concat(Array.from(str.matchAll(mbpPagebreakRegex), m => m.index))
|
||||||
.map((x, i, a) => str.slice(x, a[i + 1]))
|
.map((start, i, a) => {
|
||||||
// recover the original raw bytes
|
const end = a[i + 1] ?? array.length
|
||||||
.map(str => Uint8Array.from(str, x => x.charCodeAt(0)))
|
return { book: this, raw: array.subarray(start, end) }
|
||||||
.map(raw => ({ book: this, raw }))
|
})
|
||||||
// get start and end filepos for each section
|
// get start and end filepos for each section
|
||||||
.reduce((arr, x) => {
|
.map((section, i, arr) => {
|
||||||
const last = arr[arr.length - 1]
|
section.start = arr[i - 1]?.end ?? 0
|
||||||
x.start = last?.end ?? 0
|
section.end = section.start + section.raw.byteLength
|
||||||
x.end = x.start + x.raw.byteLength
|
return section
|
||||||
return arr.concat(x)
|
})
|
||||||
}, [])
|
|
||||||
|
|
||||||
this.sections = this.#sections.map((section, index) => ({
|
this.sections = this.#sections.map((section, index) => ({
|
||||||
id: index,
|
id: index,
|
||||||
|
|||||||
Reference in New Issue
Block a user