From 084914aec6da2f0a7fb0988ec74b4796382103c8 Mon Sep 17 00:00:00 2001 From: Sithel Date: Sat, 9 Mar 2024 17:49:43 -0800 Subject: [PATCH] initial stab & functionality of spine marks --- src/book.js | 55 ++++++++++++++++++++++++++++++------- src/html/page_layout.html | 9 ++++++ src/models/configuration.js | 1 + src/signatures.js | 15 +++++++--- src/utils/drawing.js | 49 ++++++++++++++++++++++++++++++--- src/utils/formUtils.js | 1 + src/utils/renderUtils.js | 4 +++ 7 files changed, 116 insertions(+), 18 deletions(-) diff --git a/src/book.js b/src/book.js index af666c1..7f9c0a9 100644 --- a/src/book.js +++ b/src/book.js @@ -10,7 +10,7 @@ import { PAGE_LAYOUTS, PAGE_SIZES } from './constants.js'; import { updatePageLayoutInfo } from './utils/renderUtils.js'; import JSZip from 'jszip'; import { loadConfiguration } from './utils/formUtils.js'; -import { drawFoldlines, drawCropmarks, drawSpineMarks } from './utils/drawing.js'; +import { drawFoldlines, drawCropmarks, drawSpineMark, drawSigOrderMark } from './utils/drawing.js'; import { calculateDimensions, calculateLayout } from './utils/layout.js'; import { interleavePages, embedPagesInNewPdf } from './utils/pdf.js'; @@ -21,6 +21,7 @@ import { interleavePages, embedPagesInNewPdf } from './utils/pdf.js'; * @property {string|number} info - page # or 'b' * @property {boolean} isSigStart * @property {boolean} isSigEnd + * @property {number} signatureNum - which signature is this page in. 0 based */ /** @@ -81,6 +82,7 @@ export class Book { this.flyleafs = configuration.flyleafs; this.cropmarks = configuration.cropMarks; this.pdfEdgeMarks = configuration.pdfEdgeMarks; + this.sigOrderMarks = configuration.sigOrderMarks; this.cutmarks = configuration.cutMarks; this.format = configuration.sigFormat; if (configuration.sigFormat === 'standardsig') { @@ -308,7 +310,7 @@ export class Book { this.format == 'customsig' ) { // Only generate the first signature for preview - const pagesArr = isPreview ? this.rearrangedpages.slice(0, 1) : this.rearrangedpages; + const pagesArr = this.rearrangedpages; const signatures = [{}]; const makeSignatures = async () => { const tasks = pagesArr.map(async (pages, i) => { @@ -316,6 +318,7 @@ export class Book { signatures[i] = { name: `${this.filename}_signature${i}` }; [signatures[i].front, signatures[i].back] = await this.createSignatures({ pageIndexDetails: pages, + maxSigCount: pagesArr.length }); }); await Promise.all(tasks); @@ -332,7 +335,8 @@ export class Book { await Promise.all(tasks); }; await duplexSignatures(); - previewPdf = signatures[0].duplex; + console.log("Shark") + // previewPdf = signatures[0].duplex; } if (this.print_file != 'aggregated' && !isPreview) { @@ -353,7 +357,7 @@ export class Book { await saveSignatures(); } - if (this.print_file != 'signatures' && !isPreview) { + if (this.print_file != 'signatures') { const saveAggregate = async () => { const aggregate = { front: !this.duplex ? await PDFDocument.create() : null, @@ -399,8 +403,11 @@ export class Book { this.zip.file(`${this.filename}_typeset.pdf`, pdfBytes); }); } + console.log("Do I have this? ",aggregate.duplex.getPageCount()) + previewPdf = aggregate.duplex + return aggregate }; - await saveAggregate(); + var results = await saveAggregate(); } var rotationMetaInfo = @@ -450,14 +457,17 @@ export class Book { * (conditionally) populates the destPdf and (conditionally) generates the outname PDF * * @param {Object} config - object /w the following parameters: - * @param {PageInfo[]} config.pageList : objects that contain 3 values: { isSigStart: boolean, isSigEnd: boolean, info: either the page number or 'b'} + * @param {PageInfo[]} config.pageList : see documentation at top of file * @param {boolean} config.back : is 'back' of page (boolean) * @param {boolean} config.alt : alternate pages (boolean) + * @param {number} config.maxSigCount * @return reference to the new PDF created */ async writepages(config) { + console.log("Write pages ", config) const pagelist = config.pageList; const back = config.back; + const maxSigCount = config.maxSigCount; const filteredList = []; const blankIndices = []; pagelist.forEach((pageInfo, i) => { @@ -467,6 +477,7 @@ export class Book { blankIndices.push(i); } }); + const [outPDF, embeddedPages] = await embedPagesInNewPdf(this.managedDoc, filteredList); blankIndices.forEach((i) => embeddedPages.splice(i, 0, 'b')); @@ -482,7 +493,7 @@ export class Book { let side2flag = back; while (block_end <= pagelist.length) { - const sigDetails = config.pageList.slice(block_start, block_end); + const sigDetails = pagelist.slice(block_start, block_end); side2flag = this.draw_block_onto_page({ outPDF: outPDF, embeddedPages: embeddedPages, @@ -492,10 +503,12 @@ export class Book { papersize: this.papersize, positions: positions, cropmarks: this.cropmarks, + sigOrderMarks: this.sigOrderMarks, pdfEdgeMarks: this.pdfEdgeMarks, cutmarks: this.cutmarks, alt: config.alt, side2flag: side2flag, + maxSigCount: maxSigCount, }); block_start += offset; block_end += offset; @@ -507,7 +520,8 @@ export class Book { * * @param {Object} config - object /w the following parameters: * @param {string|null} config.outname : name of pdf added to ongoing zip file. Ex: 'signature1duplex.pdf' (or null if no signature file needed) - * @param {PageInfo[]} config.sigDetails : objects that contain 3 values: { isSigStart: boolean, isSigEnd: boolean, info: either the page number or 'b'} + * @param {PageInfo[]} config.sigDetails : see documentation at top of file + * @param {number} config.maxSigCount: Total number of signatures * @param {boolean} config.side2flag : is 'back' of page (boolean) * @param {[number, number]} config.papersize : paper size (as [number, number]) * @param {number} config.block_start: Starting page index @@ -529,10 +543,13 @@ export class Book { const outPDF = config.outPDF; const positions = config.positions; const foldmarks = config.cropmarks; + const sigOrderMarks = config.sigOrderMarks; const pdfEdgeMarks = config.pdfEdgeMarks; const cutmarks = config.cutmarks; const alt = config.alt; + const maxSigCount = config.maxSigCount let side2flag = config.side2flag; + console.log("burp I see ",maxSigCount) const block = config.embeddedPages.slice(block_start, block_end); const currPage = outPDF.addPage(papersize); @@ -541,6 +558,7 @@ export class Book { ? drawFoldlines(side2flag, this.duplexrotate, papersize, this.per_sheet) : []; const drawLines = [...cropLines, ...foldLines]; + const drawRects = []; block.forEach((page, i) => { if (page == 'b' || page === undefined) { @@ -558,14 +576,27 @@ export class Book { console.error('Unexpected type for page: ', page); } - if (pdfEdgeMarks && (sigDetails[i].isSigStart || sigDetails[i].isSigEnd)) { - drawLines.push(drawSpineMarks(sigDetails[i], positions[i])); + if (sigDetails[i].isSigStart) { + if (pdfEdgeMarks) { + drawLines.push(drawSpineMark(true, positions[i], 5)); + } + if (sigOrderMarks) { + drawRects.push(drawSigOrderMark(sigDetails[i], positions[i], maxSigCount, 5, 20)); + } + } + else if (sigDetails[i].isSigEnd) { + if (pdfEdgeMarks) { + drawLines.push(drawSpineMark(false, positions[i], 5)); + } } }); drawLines.forEach((line) => { currPage.drawLine(line); }); + drawRects.forEach((rect) => { + currPage.drawRectangle(rect); + }) if (alt) { side2flag = !side2flag; @@ -577,20 +608,24 @@ export class Book { * PDF builder base function for Classic (non-Wacky) layouts. Called by [createoutputfiles] * * @param {Object} config + * @param {number} config.maxSigCount * @param {PageInfo[][]} config.pageIndexDetails : a nested list of objects. */ async createSignatures(config) { + console.log("createSignatures ",config) const pages = config.pageIndexDetails; const tasks = [ this.writepages({ pageList: pages[0], back: false, alt: false, + maxSigCount: config.maxSigCount, }), this.writepages({ pageList: pages[1], back: true, alt: false, + maxSigCount: config.maxSigCount, }), ]; const [pdfFront, pdfBack] = await Promise.all(tasks); diff --git a/src/html/page_layout.html b/src/html/page_layout.html index 4b55021..8b92f77 100644 --- a/src/html/page_layout.html +++ b/src/html/page_layout.html @@ -34,6 +34,15 @@

Page Layout

data-balloon-pos="up" >
+ diff --git a/src/models/configuration.js b/src/models/configuration.js index 27f370c..181c5b0 100644 --- a/src/models/configuration.js +++ b/src/models/configuration.js @@ -82,6 +82,7 @@ export const schema = z.object({ cropMarks: urlSafe(coercedBoolean).default(false), cutMarks: urlSafe(coercedBoolean).default(false), pdfEdgeMarks: urlSafe(coercedBoolean).default(false), + sigOrderMarks: urlSafe(coercedBoolean).default(false), pageScaling, pagePositioning, mainForeEdgePaddingPt: urlSafe(z.coerce.number()).default(0), diff --git a/src/signatures.js b/src/signatures.js index 4a35528..0db40ed 100644 --- a/src/signatures.js +++ b/src/signatures.js @@ -77,12 +77,13 @@ export class Signatures { const newsigs = []; // Use the booklet class for each signature - this.signaturepagelists.forEach((pagerange) => { + this.signaturepagelists.forEach((pagerange, i) => { const pagelistdetails = this.booklet( pagerange, this.duplex, this.per_sheet, - this.duplexrotate + this.duplexrotate, + i ); newsigs.push(pagelistdetails); }); @@ -122,8 +123,9 @@ export class Signatures { * @param {boolean} duplex - Whether both front and back sides go in the same file or not. * @param {number} per_sheet - number of pages per sheet (front and back combined) * @param {boolean} duplexrotate - whether to rotate alternating sheets or not. + * @param {number} sig_num - signature number (0 indexed) */ - booklet(pages, duplex, per_sheet, duplexrotate) { + booklet(pages, duplex, per_sheet, duplexrotate, sig_num) { const pagelistdetails = duplex ? [[]] : [[], []]; const { front, rotate, back } = BOOKLET_LAYOUTS[per_sheet]; @@ -139,19 +141,21 @@ export class Signatures { let front_end = center; let back_start = center; let back_end = center + pageblock; - + console.log("outside") while (front_start >= 0 && back_end <= pages.length) { const front_block = pages.slice(front_start, front_end); const back_block = pages.slice(back_start, back_end); const block = [...front_block, ...back_block]; + console.log(" ~~~~ SIG NUM "+sig_num+" on "+front_start+" --> "+back_end) front_config.forEach((pnum) => { const page = block[pnum - 1]; //page layouts are 1-indexed, not 0-index pagelistdetails[0].push({ info: page, isSigStart: front_start == 0 && pnum == 1, isSigEnd: front_start == 0 && pnum == block.length, + signatureNum: sig_num, }); }); @@ -163,11 +167,14 @@ export class Signatures { info: page, isSigStart: front_start == 0 && pnum == 1, isSigEnd: front_start == 0 && pnum == block.length, + signatureNum: sig_num, }); }); // Update all our counters + console.log("stepa "+front_start) front_start -= pageblock; + console.log("stepb "+front_start) front_end -= pageblock; back_start += pageblock; back_end += pageblock; diff --git a/src/utils/drawing.js b/src/utils/drawing.js index 9b366c8..6e26411 100644 --- a/src/utils/drawing.js +++ b/src/utils/drawing.js @@ -113,14 +113,14 @@ export function drawCropmarks(papersize, per_sheet) { } /** - * @param {import("../book.js").PageInfo} sigDetails - page info object + * @param {boolean} draw_top_mark - true to draw mark at top of PDF, false for bottom of PDF * @param {import("../book.js").Position} position - position info object + * @param {number} w - width of the line in pts * @returns {Line} */ -export function drawSpineMarks(sigDetails, position) { - const w = 5; +export function drawSpineMark(draw_top_mark, position, w) { let startX, startY, endX, endY; - if (sigDetails.isSigStart) { + if (draw_top_mark) { [startX, startY] = position.spineMarkTop; [endX, endY] = position.spineMarkTop; } else { @@ -148,6 +148,47 @@ export function drawSpineMarks(sigDetails, position) { return drawLineArgs; } + +/** + * @param {import("../book.js").PageInfo} sigDetails - page info object + * @param {import("../book.js").Position} position - position info object + * @param {number} maxSigCount - number of total signatures + * @param {number} w - width of the mark in pts + * @param {number} suggested_h - suggested height of the mark in pts (can be scaled down to fit all marks between PDF top/bottom) + * @returns {Line} + */ +export function drawSigOrderMark(sigDetails, position, maxSigCount, w, suggested_h) { + const top = drawSpineMark(true, position, w); + const bottom = drawSpineMark(false, position, w); + + let x = top.start.x + let y = top.start.y + + const dist = (position.rotation == 0) ? top.start.y - bottom.start.y : top.start.x - bottom.start.x + let h = Math.min(suggested_h, dist/maxSigCount) + const offset = h * sigDetails.signatureNum; + console.log("Looking at signature ",sigDetails.signatureNum," of ",maxSigCount," PDF top/bottom distance ",dist," results in ",h," (",suggested_h," vs ",(dist/maxSigCount),") order mark height w/ offset ",offset," (width ",w,")") + + if (position.rotation == 0) { + h = h * -1; + y -= offset; + } else { + const temp = h; + h = w; + w = temp * -1; + x -= offset + } + + return { + x: x, + y: y, + width: w, + height: h, + borderWidth: 0, + color: rgb(0, 0, 0), + opacity: 0.5, + }; +} /** * @param {number} x * @param {number} ystart diff --git a/src/utils/formUtils.js b/src/utils/formUtils.js index a477b5b..68eccef 100644 --- a/src/utils/formUtils.js +++ b/src/utils/formUtils.js @@ -22,6 +22,7 @@ const fromFormToConfiguration = (form) => paperRotation90: form.has('paper_rotation_90'), pageLayout: form.get('pagelayout'), cropMarks: form.has('cropmarks'), + sigOrderMarks: form.has('sig_order_marks'), pdfEdgeMarks: form.has('pdf_edge_marks'), cutMarks: form.has('cutmarks'), pageScaling: form.get('page_scaling'), diff --git a/src/utils/renderUtils.js b/src/utils/renderUtils.js index b627be1..ab48097 100644 --- a/src/utils/renderUtils.js +++ b/src/utils/renderUtils.js @@ -183,6 +183,10 @@ export function renderFormFromSettings(configuration) { document.querySelector("input[name='cropmarks']").checked = true; } + if (configuration.sigOrderMarks) { + document.querySelector("input[name='sig_order_marks']").checked = true; + } + if (configuration.pdfEdgeMarks) { document.querySelector("input[name='pdf_edge_marks']").checked = true; }