diff --git a/src/book.js b/src/book.js index 2c5e49e..725cc18 100644 --- a/src/book.js +++ b/src/book.js @@ -298,7 +298,7 @@ export class Book { async createoutputfiles(isPreview) { const previewFrame = document.getElementById('pdf'); previewFrame.style.display = 'none'; - let resultPDF = null; + let previewPdf = null; // create a directory named after the input pdf and fill it with // the signatures @@ -316,102 +316,123 @@ export class Book { this.format == 'standardsig' || this.format == 'customsig' ) { - const generateAggregate = this.print_file != 'signatures'; - const generateSignatures = this.print_file != 'aggregated'; - let aggregatePdf0, aggregatePdf1; - if (generateAggregate) { - aggregatePdf0 = await PDFDocument.create(); - aggregatePdf1 = this.duplex ? null : await PDFDocument.create(); + // Only generate the first signature for preview + const pagesArr = isPreview ? this.rearrangedpages.slice(0, 1) : this.rearrangedpages; + const signatures = [{}]; + const makeSignatures = async () => { + await Promise.all( + pagesArr.map(async (pages, i) => { + console.log(pages); + signatures[i] = { name: `${this.filename}_signature${i}` }; + [signatures[i].front, signatures[i].back] = await this.createSignatures({ + pageIndexDetails: pages, + }); + }) + ); + }; + await makeSignatures(); + + // always duplex for preview + if (this.duplex || isPreview) { + const duplexSignatures = async () => { + await Promise.all( + signatures.map(async (sig, i) => { + signatures[i].duplex = await interleavePages(sig.front, sig.back); + signatures[i].back = signatures[i].front = null; + }) + ); + }; + await duplexSignatures(); + previewPdf = signatures[0].duplex; } - const forLoop = async () => { - for (let i = 0; i < this.rearrangedpages.length; i++) { - const signature = this.rearrangedpages[i]; - console.log(signature); - const sigName = `${this.filename}_signature${i}`; - const [sigFront, sigBack] = await this.createSignatures({ - pageIndexDetails: signature, - }); - - if (this.duplex) { - // collate - const sig = await interleavePages(sigFront, sigBack); - if (generateSignatures) { - await sig.save().then((pdfBytes) => { - this.zip.file(`signatures/${sigName}_duplex`, pdfBytes); + if (this.print_file != 'aggregated' && !isPreview) { + const saveSignatures = async () => { + await Promise.all( + signatures.map(async (sig) => { + await sig.front?.save().then((pdfBytes) => { + this.zip.file(`signatures/${sig.name}_side1`, pdfBytes); }); - } - - if (generateAggregate) { - const copiedPages = await aggregatePdf0.copyPages(sig, sig.getPageIndices()); - copiedPages.forEach((page) => aggregatePdf0.addPage(page)); - } - } else { - if (generateSignatures) { - await sigFront.save().then((pdfBytes) => { - this.zip.file(`signatures/${sigName}_side1`, pdfBytes); + await sig.back?.save().then((pdfBytes) => { + this.zip.file(`signatures/${sig.name}_side2`, pdfBytes); }); - await sigBack.save().then((pdfBytes) => { - this.zip.file(`signatures/${sigName}_side2`, pdfBytes); + await sig.duplex?.save().then((pdfBytes) => { + this.zip.file(`signatures/${sig.name}_duplex`, pdfBytes); }); - } + }) + ); + }; + await saveSignatures(); + } - if (generateAggregate) { - const copiedPagesFront = await aggregatePdf0.copyPages( - sigFront, - sigFront.getPageIndices() + if (this.print_file != 'signatures' && !isPreview) { + const saveAggregate = async () => { + const aggregate = { + front: !this.duplex ? await PDFDocument.create() : null, + back: !this.duplex ? await PDFDocument.create() : null, + duplex: this.duplex ? await PDFDocument.create() : null, + }; + for (const sig of signatures) { + // Adding pages to aggregate PDFs has to be done in order, not with promises + if (aggregate.front) { + const copiedPages = await aggregate.front.copyPages( + sig.front, + sig.front.getPageIndices() ); - copiedPagesFront.forEach((page) => aggregatePdf0.addPage(page)); - - const copiedPagesBack = await aggregatePdf1.copyPages( - sigBack, - sigBack.getPageIndices() + copiedPages.forEach((page) => aggregate.front.addPage(page)); + } + if (aggregate.back) { + const copiedPages = await aggregate.back.copyPages( + sig.back, + sig.back.getPageIndices() + ); + copiedPages.forEach((page) => aggregate.back.addPage(page)); + } + if (aggregate.duplex) { + const copiedPages = await aggregate.duplex.copyPages( + sig.duplex, + sig.duplex.getPageIndices() ); - copiedPagesBack.forEach((page) => aggregatePdf1.addPage(page)); + copiedPages.forEach((page) => aggregate.duplex.addPage(page)); } } - } - }; - await forLoop(); - - if (aggregatePdf1 != null) { - await aggregatePdf1.save().then((pdfBytes) => { - if (!isPreview) this.zip.file(`${this.filename}_typeset_side2.pdf`, pdfBytes); - }); - } - if (aggregatePdf0 != null) { - await aggregatePdf0.save().then((pdfBytes) => { - if (!isPreview) - this.zip.file( - this.duplex ? `${this.filename}_typeset.pdf` : `${this.filename}_typeset_side1.pdf`, - pdfBytes - ); - }); + aggregate.front?.save().then((pdfBytes) => { + this.zip.file(`${this.filename}_typeset_side1.pdf`, pdfBytes); + }); + aggregate.back?.save().then((pdfBytes) => { + this.zip.file(`${this.filename}_typeset_side2.pdf`, pdfBytes); + }); + aggregate.duplex?.save().then((pdfBytes) => { + this.zip.file(`${this.filename}_typeset.pdf`, pdfBytes); + }); + }; + await saveAggregate(); } + var rotationMetaInfo = (this.paper_rotation_90 ? 'paper_rotated' : '') + (this.source_rotation == 'none' ? '' : `_${this.source_rotation}`); this.filename = `${origFileName}${rotationMetaInfo}`; } else if (this.format == 'a9_3_3_4') { - resultPDF = await this.buildSheets(this.filename, this.book.a9_3_3_4_builder()); + previewPdf = await this.buildSheets(this.filename, this.book.a9_3_3_4_builder()); } else if (this.format == 'a10_6_10s') { - resultPDF = await this.buildSheets(this.filename, this.book.a10_6_10s_builder()); + previewPdf = await this.buildSheets(this.filename, this.book.a10_6_10s_builder()); } else if (this.format == 'a_4_8s') { - resultPDF = await this.buildSheets(this.filename, this.book.a_4_8s_builder()); + previewPdf = await this.buildSheets(this.filename, this.book.a_4_8s_builder()); } else if (this.format == 'a_3_6s') { - resultPDF = await this.buildSheets(this.filename, this.book.a_3_6s_builder()); + previewPdf = await this.buildSheets(this.filename, this.book.a_3_6s_builder()); } else if (this.format == 'A7_2_16s') { - resultPDF = await this.buildSheets(this.filename, this.book.a7_2_16s_builder()); + previewPdf = await this.buildSheets(this.filename, this.book.a7_2_16s_builder()); } else if (this.format == '1_3rd') { - resultPDF = await this.buildSheets(this.filename, this.book.page_1_3rd_builder()); + previewPdf = await this.buildSheets(this.filename, this.book.page_1_3rd_builder()); } else if (this.format == '8_zine') { - resultPDF = await this.buildSheets(this.filename, this.book.page_8_zine_builder()); + previewPdf = await this.buildSheets(this.filename, this.book.page_8_zine_builder()); } - console.log('Attempting to generate preview for ', resultPDF); + console.log('Attempting to generate preview for ', previewPdf); - if (resultPDF != null) { - const pdfDataUri = await resultPDF.saveAsBase64({ dataUri: true }); - const viewerPrefs = resultPDF.catalog.getOrCreateViewerPreferences(); + if (previewPdf != null) { + const pdfDataUri = await previewPdf.saveAsBase64({ dataUri: true }); + const viewerPrefs = previewPdf.catalog.getOrCreateViewerPreferences(); viewerPrefs.setHideToolbar(false); viewerPrefs.setHideMenubar(false); viewerPrefs.setHideWindowUI(false); diff --git a/src/utils/pdf.js b/src/utils/pdf.js index 47cd917..7bc264f 100644 --- a/src/utils/pdf.js +++ b/src/utils/pdf.js @@ -11,14 +11,21 @@ import { PDFDocument } from 'pdf-lib'; export async function interleavePages(pdfA, pdfB) { const mergedPdf = await PDFDocument.create(); const pageCount = Math.max(pdfA.getPageCount(), pdfB.getPageCount()); + const promises = []; + for (let i = 0; i < pageCount; i++) { - const pageA = pdfA.getPage(i); - if (pageA) mergedPdf.addPage((await mergedPdf.copyPages(pdfA, [i]))[0]); + const pageAPromise = pdfA.getPage(i); + const pageBPromise = pdfB.getPage(i); + + promises.push(pageAPromise, pageBPromise); - const pageB = pdfB.getPage(i); + const [pageA, pageB] = await Promise.all([pageAPromise, pageBPromise]); + + if (pageA) mergedPdf.addPage((await mergedPdf.copyPages(pdfA, [i]))[0]); if (pageB) mergedPdf.addPage((await mergedPdf.copyPages(pdfB, [i]))[0]); } + await Promise.all(promises); // Wait for all page retrieval promises to resolve return mergedPdf; }