/* Markings mixin - support marked content sequences in content streams By Ben Schmidt */ import PDFStructureElement from "../structure_element"; import PDFStructureContent from "../structure_content"; import PDFNumberTree from "../number_tree"; import PDFObject from "../object"; export default { initMarkings(options) { this.structChildren = []; if (options.tagged) { this.getMarkingsDictionary().data.Marked = true; } }, markContent(tag, options = null) { if (tag === 'Artifact' || (options && options.mcid)) { let toClose = 0; this.page.markings.forEach((marking) => { if (toClose || marking.structContent || marking.tag === 'Artifact') { toClose++; } }); while (toClose--) { this.endMarkedContent(); } } if (!options) { this.page.markings.push({ tag }); this.addContent(`/${tag} BMC`); return this; } this.page.markings.push({ tag, options }); const dictionary = {}; if (typeof options.mcid !== 'undefined') { dictionary.MCID = options.mcid; } if (tag === 'Artifact') { if (typeof options.type === 'string') { dictionary.Type = options.type; } if (Array.isArray(options.bbox)) { dictionary.BBox = [options.bbox[0], this.page.height - options.bbox[3], options.bbox[2], this.page.height - options.bbox[1]]; } if (Array.isArray(options.attached) && options.attached.every(val => typeof val === 'string')) { dictionary.Attached = options.attached; } } if (tag === 'Span') { if (options.lang) { dictionary.Lang = new String(options.lang); } if (options.alt) { dictionary.Alt = new String(options.alt); } if (options.expanded) { dictionary.E = new String(options.expanded); } if (options.actual) { dictionary.ActualText = new String(options.actual); } } this.addContent(`/${tag} ${PDFObject.convert(dictionary)} BDC`); return this; }, markStructureContent(tag, options = {}) { const pageStructParents = this.getStructParentTree().get(this.page.structParentTreeKey); const mcid = pageStructParents.length; pageStructParents.push(null); this.markContent(tag, { ...options, mcid }); const structContent = new PDFStructureContent(this.page.dictionary, mcid); this.page.markings.slice(-1)[0].structContent = structContent; return structContent; }, endMarkedContent() { this.page.markings.pop(); this.addContent('EMC'); return this; }, struct(type, options = {}, children = null) { return new PDFStructureElement(this, type, options, children); }, addStructure(structElem) { const structTreeRoot = this.getStructTreeRoot(); structElem.setParent(structTreeRoot); structElem.setAttached(); this.structChildren.push(structElem); if (!structTreeRoot.data.K) { structTreeRoot.data.K = []; } structTreeRoot.data.K.push(structElem.dictionary); return this; }, initPageMarkings(pageMarkings) { pageMarkings.forEach((marking) => { if (marking.structContent) { const structContent = marking.structContent; const newStructContent = this.markStructureContent(marking.tag, marking.options); structContent.push(newStructContent); this.page.markings.slice(-1)[0].structContent = structContent; } else { this.markContent(marking.tag, marking.options); } }); }, endPageMarkings(page) { const pageMarkings = page.markings; pageMarkings.forEach(() => page.write('EMC')); page.markings = []; return pageMarkings; }, getMarkingsDictionary() { if (!this._root.data.Markings) { this._root.data.Markings = this.ref({}); } return this._root.data.Markings; }, getStructTreeRoot() { if (!this._root.data.StructTreeRoot) { this._root.data.StructTreeRoot = this.ref({ Type: "StructTreeRoot", ParentTree: new PDFNumberTree(), ParentTreeNextKey: 0 }); } return this._root.data.StructTreeRoot; }, getStructParentTree() { return this.getStructTreeRoot().data.ParentTree; }, createStructParentTreeNextKey() { // initialise the Markings dictionary this.getMarkingsDictionary(); const structTreeRoot = this.getStructTreeRoot(); const key = structTreeRoot.data.ParentTreeNextKey++; structTreeRoot.data.ParentTree.add(key, []); return key; }, endMarkings() { const structTreeRoot = this._root.data.StructTreeRoot; if (structTreeRoot) { structTreeRoot.end(); this.structChildren.forEach((structElem) => structElem.end()); } if (this._root.data.Markings) { this._root.data.Markings.end(); } } };