KF8: fix embedded images in SVG

This commit is contained in:
John Factotum
2023-09-11 12:53:09 +08:00
parent 83e709f575
commit ab6048411a
+23 -12
View File
@@ -884,6 +884,7 @@ const replaceSeries = async (str, regex, f) => {
class KF8 { class KF8 {
parser = new DOMParser() parser = new DOMParser()
serializer = new XMLSerializer()
#cache = new Map() #cache = new Map()
#fragmentOffsets = new Map() #fragmentOffsets = new Map()
#fragmentSelectors = new Map() #fragmentSelectors = new Map()
@@ -894,8 +895,8 @@ class KF8 {
#rawTail = new Uint8Array() #rawTail = new Uint8Array()
#lastLoadedHead = -1 #lastLoadedHead = -1
#lastLoadedTail = -1 #lastLoadedTail = -1
#checkType = true
#type = MIME.XHTML #type = MIME.XHTML
#inlineMap = new Map()
constructor(mobi) { constructor(mobi) {
this.mobi = mobi this.mobi = mobi
} }
@@ -1029,12 +1030,18 @@ class KF8 {
: await this.mobi.loadResource(id - 1) : await this.mobi.loadResource(id - 1)
const result = [MIME.XHTML, MIME.HTML, MIME.CSS, MIME.SVG].includes(type) const result = [MIME.XHTML, MIME.HTML, MIME.CSS, MIME.SVG].includes(type)
? await this.replaceResources(this.mobi.decode(raw)) : raw ? await this.replaceResources(this.mobi.decode(raw)) : raw
return new Blob([result], { type }) const doc = type === MIME.SVG ? this.parser.parseFromString(result, type) : null
return [new Blob([result], { type }),
// SVG wrappers need to be inlined
// as browsers don't allow external resources when loading SVG as an image
doc?.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'image')?.length
? doc.documentElement : null]
} }
async loadResource(str) { async loadResource(str) {
if (this.#cache.has(str)) return this.#cache.get(str) if (this.#cache.has(str)) return this.#cache.get(str)
const blob = await this.loadResourceBlob(str) const [blob, inline] = await this.loadResourceBlob(str)
const url = URL.createObjectURL(blob) const url = inline ? str : URL.createObjectURL(blob)
if (inline) this.#inlineMap.set(url, inline)
this.#cache.set(str, url) this.#cache.set(str, url)
return url return url
} }
@@ -1102,16 +1109,20 @@ class KF8 {
async loadSection(section) { async loadSection(section) {
if (this.#cache.has(section)) return this.#cache.get(section) if (this.#cache.has(section)) return this.#cache.get(section)
const str = await this.loadText(section) const str = await this.loadText(section)
const replaced = await this.replaceResources(str)
// by default, type is XHTML; change to HTML if it's not valid XHTML // by default, type is XHTML; change to HTML if it's not valid XHTML
if (this.#checkType && this.parser let doc = this.parser.parseFromString(replaced, this.#type)
.parseFromString(str, this.#type) if (doc.querySelector('parsererror')) {
.querySelector('parsererror')) this.#type = MIME.HTML this.#type = MIME.HTML
// let's just check it once for now doc = this.parser.parseFromString(replaced, this.#type)
if (this.#checkType) this.#checkType = false }
for (const [url, node] of this.#inlineMap) {
const replaced = await this.replaceResources(str) for (const el of doc.querySelectorAll(`img[src="${url}"]`))
const url = URL.createObjectURL(new Blob([replaced], { type: this.#type })) el.replaceWith(node)
}
const url = URL.createObjectURL(
new Blob([this.serializer.serializeToString(doc)], { type: this.#type }))
this.#cache.set(section, url) this.#cache.set(section, url)
return url return url
} }