Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

initial stab & functionality of spine marks #109

Merged
merged 12 commits into from
May 7, 2024
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ <h1>Bookbinder JS</h1>
<load src="src/html/source_manip.html" />
<load src="src/html/printer.html" />
<load src="src/html/page_layout.html" />
<load src="src/html/crop_box.html" />
<load src="src/html/sig_format.html" />
<load src="src/html/flyleaf.html" />
<load src="src/html/preview.html" />
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bookbinder",
"version": "1.5.0",
"version": "1.6.0",
"description": "An app to rearrange PDF pages for printing for bookbinding",
"type": "module",
"scripts": {
Expand Down
74 changes: 55 additions & 19 deletions src/book.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@ 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, drawSewingMarks } from './utils/drawing.js';
import {
drawFoldlines,
drawCropmarks,
drawSpineMark,
drawSigOrderMark,
drawSewingMarks,
} from './utils/drawing.js';
import { calculateDimensions, calculateLayout } from './utils/layout.js';
import { interleavePages, embedPagesInNewPdf } from './utils/pdf.js';

Expand All @@ -21,6 +27,8 @@ import { interleavePages, embedPagesInNewPdf } from './utils/pdf.js';
* @property {string|number} info - page # or 'b'
* @property {boolean} isSigStart
* @property {boolean} isSigEnd
* @property {boolean} isSigMiddle
* @property {number} signatureNum - which signature is this page in. 0 based
*/

/**
Expand Down Expand Up @@ -90,12 +98,14 @@ export class Book {
this.flyleafs = configuration.flyleafs;
this.cropmarks = configuration.cropMarks;
this.sewingMarks = {
sewingMarkLocation: configuration.sewingMarkLocation,
isEnabled: configuration.sewingMarksEnabled,
amount: configuration.sewingMarksAmount,
marginPt: configuration.sewingMarksMarginPt,
tapeWidthPt: configuration.sewingMarksTapeWidthPt,
};
this.pdfEdgeMarks = configuration.pdfEdgeMarks;
this.sigOrderMarks = configuration.sigOrderMarks;
this.cutmarks = configuration.cutMarks;
this.format = configuration.sigFormat;
if (configuration.sigFormat === 'standardsig') {
Expand Down Expand Up @@ -229,13 +239,6 @@ export class Book {
this.cropbox = newPage.getCropBox();
}

console.log(
'The updatedDoc doc has : ',
this.managedDoc.getPages(),
' vs --- ',
this.managedDoc.getPageCount()
);

switch (this.format) {
case 'perfect':
case 'booklet':
Expand Down Expand Up @@ -303,6 +306,8 @@ export class Book {
* generate preview content AND a downloadable zip
*/
async createoutputfiles(isPreview) {
// set this to `true` to enable full-book previews (placeholder till it's in the UI)
const fullPreviewDevHack = true;
sithel marked this conversation as resolved.
Show resolved Hide resolved
const previewFrame = document.getElementById('pdf');
let previewPdf = null;

Expand All @@ -323,14 +328,16 @@ 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 =
isPreview && !fullPreviewDevHack ? this.rearrangedpages.slice(0, 1) : this.rearrangedpages;
const signatures = [{}];
const makeSignatures = async () => {
const tasks = pagesArr.map(async (pages, i) => {
console.log(pages);
signatures[i] = { name: `${this.filename}_signature${i}` };
[signatures[i].front, signatures[i].back] = await this.createSignatures({
[signatures[i].front, signatures[i].back] = await this.createSignature({
pageIndexDetails: pages,
maxSigCount: pagesArr.length,
});
});
await Promise.all(tasks);
Expand All @@ -350,7 +357,7 @@ export class Book {
previewPdf = signatures[0].duplex;
}

if (this.print_file != 'aggregated' && !isPreview) {
if (this.print_file != 'aggregated' && (!isPreview || fullPreviewDevHack)) {
const saveSignatures = async () => {
const tasks = signatures.map(async (sig) => {
await sig.front?.save().then((pdfBytes) => {
Expand All @@ -368,7 +375,7 @@ export class Book {
await saveSignatures();
}

if (this.print_file != 'signatures' && !isPreview) {
if (this.print_file != 'signatures' && (!isPreview || fullPreviewDevHack)) {
const saveAggregate = async () => {
const aggregate = {
front: !this.duplex ? await PDFDocument.create() : null,
Expand Down Expand Up @@ -414,7 +421,9 @@ export class Book {
this.zip.file(`${this.filename}_typeset.pdf`, pdfBytes);
});
}
previewPdf = aggregate.duplex;
};

await saveAggregate();
}

Expand Down Expand Up @@ -461,18 +470,20 @@ export class Book {
}

/**
* Part of the Classic (non-Wacky) flow. Called by [createsignatures].
* Part of the Classic (non-Wacky) flow. Called by [createsignature].
* (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) {
const pagelist = config.pageList;
const back = config.back;
const maxSigCount = config.maxSigCount;
const filteredList = [];
const blankIndices = [];
pagelist.forEach((pageInfo, i) => {
Expand All @@ -482,6 +493,7 @@ export class Book {
blankIndices.push(i);
}
});

const [outPDF, embeddedPages] = await embedPagesInNewPdf(this.managedDoc, filteredList);

blankIndices.forEach((i) => embeddedPages.splice(i, 0, 'b'));
Expand All @@ -497,7 +509,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,
Expand All @@ -507,10 +519,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,
sewingMarks: this.sewingMarks,
});
block_start += offset;
Expand All @@ -523,7 +537,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
Expand All @@ -546,9 +561,11 @@ 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;
const sewingMarks = config.sewingMarks;

Expand All @@ -559,6 +576,7 @@ export class Book {
? drawFoldlines(side2flag, this.duplexrotate, papersize, this.per_sheet)
: [];
const drawLines = [...cropLines, ...foldLines];
const drawRects = [];
const drawPoints = [];

block.forEach((page, i) => {
Expand All @@ -577,13 +595,23 @@ 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));
}
}
const sewingMarkPoints = sewingMarks.isEnabled
? drawSewingMarks(
sigDetails[i],
positions[i],
sewingMarks.sewingMarkLocation,
sewingMarks.amount,
sewingMarks.marginPt,
sewingMarks.tapeWidthPt
Expand All @@ -595,6 +623,9 @@ export class Book {
drawLines.forEach((line) => {
currPage.drawLine(line);
});
drawRects.forEach((rect) => {
currPage.drawRectangle(rect);
});

drawPoints.forEach((point) => {
currPage.drawCircle(point);
Expand All @@ -608,22 +639,27 @@ export class Book {

/**
* PDF builder base function for Classic (non-Wacky) layouts. Called by [createoutputfiles]
* Generates a single signature (or is it just a single sheet? -- comments left long after coding)
* TODO : re-examine this logic and clean up this comment. What is going on??
*
* @param {Object} config
* @param {number} config.maxSigCount
* @param {PageInfo[][]} config.pageIndexDetails : a nested list of objects.
*/
async createSignatures(config) {
async createSignature(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);
Expand Down
2 changes: 2 additions & 0 deletions src/book.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ describe('Book model', () => {
top: 0,
},
sewingMarks: {
sewingMarkLocation: 'all',
amount: 3,
isEnabled: false,
marginPt: 72,
Expand All @@ -57,6 +58,7 @@ describe('Book model', () => {
source_rotation: 'none',
print_file: 'both',
signatureconfig: [],
sigOrderMarks: false,
};

it('returns a new Book', () => {
Expand Down
99 changes: 99 additions & 0 deletions src/html/crop_box.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<div class="section">
<h2>PDF Markup</h2>
<i>(does not currently work with Wacky Small Layouts -- soon!)</i><br />
<span class="row">
<label
>Add Foldlines
<span
data-balloon-length="medium"
aria-label="Adds folding guidelines (ordered thickest to thinnest)"
data-balloon-pos="up"
>
<input type="checkbox" name="cropmarks" />
</span>
</label>
</span>

<span class="row">
<label
>Add Cutlines
<span data-balloon-length="medium" aria-label="Adds cutting guidelines" data-balloon-pos="up">
<input type="checkbox" name="cutmarks"
/></span>
</label>
</span>
<span class="row">
<label
>Add PDF bounds indicators (spine)
<span
data-balloon-length="medium"
aria-label="Puts small marks on the outermost folio of the signatures indicating the top and bottom of the PDF"
data-balloon-pos="up"
>
<input type="checkbox" name="pdf_edge_marks"
/></span>
</label>
</span>
<span class="row">
<label
>Add signature order marks (spine)
<span
data-balloon-length="medium"
aria-label="Puts staggered lines down the different signature spines to indicate order"
data-balloon-pos="up"
>
<input type="checkbox" name="sig_order_marks"
/></span>
</label>
</span>
<span class="row">
<label>Add marks for sewing</label>
<input type="checkbox" id="add_sewing_marks_checkbox" name="add_sewing_marks_checkbox" />
<details id="sewing_marks_details">
<summary>Detailed settings for sewing</summary>
<span class="row">
<label
>Draw marks on :
<select name="sewing_mark_locations" id="sewing_mark_locations">
<option value="all" selected="selected">center of every folio</option>
<option value="only_out">only on spine</option>
<option value="only_in">only in center of signature</option>
<option value="in_n_out">both spine and center of signature</option>
</select> </label
><br />
Look at the image below.<br />
<label
>(A) Margin (distance where first point should be draw):
<input
type="number"
id="sewing_marks_margin_pt"
name="sewing_marks_margin_pt"
class="layout_margin_user_input_field" /><sub>pt</sub><br
/></label>

<label
>(B) Amount of sewing points:
<input
type="number"
id="sewing_marks_amount"
name="sewing_marks_amount"
class="layout_margin_user_input_field" /><br
/></label>

<label
>(C) Tape width:
<input
type="number"
id="sewing_marks_tape_width_pt"
name="sewing_marks_tape_width_pt"
class="layout_margin_user_input_field" /><sub>pt</sub><br
/></label>
<img
alt="sewing image - use tape width of 0pt to make a single dot (overlapping marks)"
src="/img/sewing_settings_explanation.png"
style="height: 100%; width: 100%; object-fit: contain"
/>
</span>
</details>
</span>
</div>
Loading
Loading