Skip to content

Commit

Permalink
fold lines
Browse files Browse the repository at this point in the history
  • Loading branch information
sithel committed Jan 17, 2025
1 parent ceb508b commit 70a8fd4
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 34 deletions.
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,30 @@ You can find the logic handling this over in `helper.js` `calImpositionInfo()`
- `window.book.imposed.sheets` : List of lists. Each entry in the outer list is a sheet of paper (front and back), which contains a list of folios, which contains a list of 4 pages making up that folio. The order of the folios within a sheet is specific to the imposition. The order of the pages in the folio is front, inner left, inner right, back
- `window.book.imposed.signatures` : List of lists. Each entry in the outer list is a signature, which contains a list of folios, which contains a list of 4 pages making up the folio. The order of signatures is start of book to end of book. The order of folios in the signature is outer-most first and ends with inner-most. The order of the pages in the folio is front, inner left, inner right, back

## Markup (step 6)

Part of the `imposer.js` code - tacked on AFTER the pages have been laid out and AFTER masking -- leverages functions such as `_renderCrosshair`, `_renderFoldLine`

## Preview (step 8) / Rendering

Starts in `preview.js`'s `build` function, kicked off via `vip.refreshPreview()`. Has some initial corner case logic (first signature only?) and hard coded assumptions (always 'both sides') - but otherwise runs the same path as the Downloaded PDF (see next section)

## Download (step 9)

When rendering/building the PDF, some settings are stored in `window.book` and referenced via hard-coded links. Some settings are passed in as parameters the further along the process you go. Some settings are checked at-time-of-evaluation via `document.getElementById`
When rendering/building the PDF, some settings are stored in `window.book` and referenced via hard-coded links. Some settings are passed in as parameters the further along the process you go. Some settings are checked at-time-of-evaluation via `document.getElementById`. The poorly named `_calcDimens` collects functions and stats at the beginning of the page assembly.

- `document.getElementById("flip_paper_short").checked` : never stored, always evaluated when rendering
- all of the mark-up values/settings

Drawing on the canvas always confuses me. Some notes:

- when thinking about the `rotate` when calling `drawPage` on a `PDFPage`, remember that it pivotes around the natural "lower left" corner. That is placed where you specify w/ `x` & `y` and then it rotates around that point.
- when looking at actual physical sheet, the side with the `1` on it is the front, and it's oriented like a normal sheet (long side vertical, short side horizontal) with the `1` on the top half of the page

The general flow of rendering found in `imposer.s` goes:
- start with `imposePdf` - branch based on which type of imposition
- each imposition knows how to lay out it's folios (( this logic is hairy, not easy to read, and is meant to be a write-once sort of thing -- alter with care!))
- `_renderPage` is called by each of the individual impositions to place an embedded page at a specific location. Depending on the scalling option, it calls a helper function to do th work (`_renderPageFill`/`_renderPageFit`/`_renderPageOriginal`) - it is those functions that call `_maskPage`
- after it has placed all the pages, it renders markup

For the actual download zip file/logic itself, check out `files.js`
15 changes: 10 additions & 5 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -638,13 +638,18 @@ <h2>6. Markup</h2>
<details>
<summary>Details</summary>
<p>
This is for cross-hairs, fold/cut lines, page numbers, spine marks, punch guides, etc
When entering line weigh values, be aware that you can use decimals/go lower than <code>1</code><BR>
Fold lines are for signature assembly - they will need to be cut at some point but it doesn't have to be right away (cut during textblock trimming)<BR>
Cut lines are for signature assembly - they need to be cut at time of fold up/sewing<Br>
Cut & Fold lines will only be marked on one side of the sheet. This is the "mountain" side of the fold - you should always be able to see the fold or cut line after the fold<BR>
Crosshairs are at every non-sheet-corner intersection and are meant to be very tiny visual guides to help with alignment/folding. They are on both sides of the sheet<BR>

</p>
</details>
<div class="printed_page_markup_options">
<input type="checkbox" id="markup_fold_lines" name="markup_fold_lines" value="fold"> <label for="markup_fold_lines"> fold lines</label> <Input type=number id="fold_line_weight" placeholder="2"/> <span id="fold_line_weight_label">line weight (pt)</span></br>
<input type="checkbox" id="markup_cut_lines" name="markup_cut_lines" value="cut"> <label for="markup_cut_lines"> cut lines</label> <Input type=number id="cut_line_weight" placeholder="2"/> <span id="cut_line_weight_label">line weight (pt)</span></br>
<input type="checkbox" id="markup_crosshairs" name="markup_crosshairs" value="cross"> <label for="markup_crosshairs"> cross-hairs</label> <Input type=number id="markup_crosshairs_weight" placeholder="2"/> <span id="markup_crosshairs_weight_label">line weight (pt)</span> | <Input type=number id="markup_crosshairs_length" placeholder="15"/> <span id="markup_crosshairs_length_label">cross-hair leg length (pt)</span></br>
<input type="checkbox" id="markup_fold_lines" name="markup_fold_lines" value="fold"> <label for="markup_fold_lines"> fold lines</label> <small><Input type=number id="fold_line_weight" placeholder="2"/> <span id="fold_line_weight_label">line weight (pt)</span></small></br>
<input type="checkbox" id="markup_cut_lines" name="markup_cut_lines" value="cut"> <label for="markup_cut_lines"> cut lines</label><small> <Input type=number id="cut_line_weight" placeholder="2"/> <span id="cut_line_weight_label">line weight (pt)</span></small></br>
<input type="checkbox" id="markup_crosshairs" name="markup_crosshairs" value="cross"> <label for="markup_crosshairs"> cross-hairs</label> <small><Input type=number id="markup_crosshairs_weight" placeholder="2"/> <span id="markup_crosshairs_weight_label">line weight (pt)</span> | <Input type=number id="markup_crosshairs_length" placeholder="15"/> <span id="markup_crosshairs_length_label">cross-hair leg length (pt)</span></small></br>
<input type="checkbox" id="markup_spine_order" name="markup_spine_order" value="order"> <label for="markup_spine_order"> spine marks: order</label> <Input type=number id="markup_spine_order_weight" placeholder="2"/> <span id="markup_spine_order_weight_label">line weight (pt)</span></br>
<input type="checkbox" id="markup_spine_bounds" name="markup_spine_bounds" value="order"> <label for="markup_spine_bounds"> spine marks: bounds</label> <Input type=number id="markup_spine_bounds_weight" placeholder="2"/> <span id="markup_spine_bounds_weight_label">line weight (pt)</span></br>
<div>
Expand All @@ -659,7 +664,7 @@ <h2>6. Markup</h2>
<div>
<input type="number" id="markup_sewing_dist_top" name="markup_sewing_dist_top" placeholder="6"> <label for="markup_sewing_dist_top"> distance from head to top hole (pt)</label> <br/>
<input type="number" id="markup_sewing_dist_bottom" name="markup_sewing_dist_bottom" placeholder="5"> <label for="markup_sewing_dist_bottom"> distance from tail to bottom hole (pt)</label> <br/>
<input type="number" id="markup_sewing_count" name="markup_sewing_count" placeholder="4"> <label for="2"> count of sewing stations</label> <br/>
<input type="number" id="markup_sewing_count" name="markup_sewing_count" placeholder="4"> <label for="markup_sewing_count"> count of sewing stations</label> <br/>
<input type="number" id="markup_sewing_station_dist" name="markup_sewing_station_dist" placeholder="3"> <label for="markup_sewing_station_dist"> distance between points at each sewing station (pt)</label> <br/>
<input type="number" id="markup_sewing_dot_size" name="markup_sewing_dot_size" placeholder="2"> <label for="markup_sewing_dot_size"> guideline dot size (pt)</label>
</div>
Expand Down
87 changes: 59 additions & 28 deletions js/imposer.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ export const imposerMagic = {
}
},
_renderPageOriginal: function(new_page, embedded_page, corner_x, corner_y, w, h, orientation, is_odd) {
console.log("==[Render Original]")
const [embedded_w, embedded_h] = [embedded_page.width, embedded_page.height]
let rotation_deg = 0
switch(orientation) {
Expand All @@ -51,7 +50,7 @@ export const imposerMagic = {
y: finalPlacement.y,
xScale: finalPlacement.scale,
yScale: finalPlacement.scale,
opacity: 0.75,
opacity: 0.15,
rotate: PDFLib.degrees(rotation_deg)
})
this._maskPage(new_page, embedded_page, corner_x + window.book.physical.short_margin, corner_y + window.book.physical.long_margin, w, h, orientation);
Expand All @@ -68,7 +67,6 @@ export const imposerMagic = {
}
},
_renderPageFit: function(new_page, embedded_page, corner_x, corner_y, w, h, orientation, is_odd) {
console.log("==[Render Fit]")
const {total_w, total_h} = this._calcPadding();
const [embedded_w, embedded_h] = [embedded_page.width, embedded_page.height]
let rotation_deg = 0;
Expand Down Expand Up @@ -99,7 +97,6 @@ export const imposerMagic = {
this._maskPage(new_page, embedded_page, corner_x + window.book.physical.short_margin, corner_y + window.book.physical.long_margin, w, h, orientation);
},
_renderPageFill: function(new_page, embedded_page, corner_x, corner_y, w, h, orientation, is_odd) {
console.log("==[Render Fill]")
const {padding_i, padding_o, padding_t, padding_b, total_w, total_h} = this._calcPadding();
const [embedded_w, embedded_h] = [embedded_page.width, embedded_page.height]
let [x, y, rotation_deg] = [corner_x, corner_y, 0]
Expand Down Expand Up @@ -248,7 +245,8 @@ export const imposerMagic = {
pW : new_page.getWidth() - window.book.physical.short_margin * 2,
pH : new_page.getHeight() - window.book.physical.long_margin * 2,
renderPage : this._renderPage.bind(this),
flip_short : document.getElementById("flip_paper_short").checked
flip_short : document.getElementById("flip_paper_short").checked,
renderCrosshair : this._renderCrossHair.bind(this)
}
},
_collectValueOrPlaceholder: function(el) {
Expand All @@ -270,6 +268,16 @@ export const imposerMagic = {
thickness: weight, color: color, opacity: 0.75,
});
},
_renderFoldLine: function(new_page, x_start, y_start, x_end, y_end) {
if (!document.getElementById("markup_fold_lines").checked)
return;
const weight = this._collectValueOrPlaceholder(document.getElementById("fold_line_weight"))
const color = PDFLib.rgb(0.2, 0.75, 0.2);
new_page.drawLine({
start: { x: x_start, y: y_start}, end: { x: x_end, y: y_end },
thickness: weight, color: color, opacity: 0.75,
});
},
_handleSingle: function(new_page, pageMap, folio_list, sheet_index, is_front) {
this._renderPage(new_page, pageMap[folio_list[0]], 0, 0)
},
Expand All @@ -284,42 +292,52 @@ export const imposerMagic = {
this._renderCrossHair(new_page, 0, pH/2.0);
},
_handleQuarto: function(new_page, pageMap, folio_list, sheet_index, is_front) {
const {pW, pH, renderPage, flip_short} = this._calcDimens(new_page)
const {pW, pH, renderPage, flip_short, renderCrosshair} = this._calcDimens(new_page)
const cell_w = pW/2;
const cell_h = pH/2;
const i = (is_front) ? [[0, 0], [0,3], [1,1], [1,2]]
: (flip_short) ? [[1, 0], [1,3], [0,1], [0, 2]]
: [[0, 2], [0,1], [1,3], [1,0]]
if (folio_list.length < 1)
return
renderPage(new_page, pageMap, folio_list[i[0][0]][i[0][1]], 0, pH/2, cell_w, cell_h, UP_SIDE_DOWN)
renderPage(new_page, pageMap, folio_list[i[1][0]][i[1][1]], pW/2, pH/2, cell_w, cell_h, UP_SIDE_DOWN)
if (folio_list.length < 2)
return
renderPage(new_page, pageMap, folio_list[i[2][0]][i[2][1]], 0, 0, cell_w, cell_h, RIGHT_SIDE_UP)
renderPage(new_page, pageMap, folio_list[i[3][0]][i[3][1]], pW/2, 0, cell_w, cell_h, RIGHT_SIDE_UP)
if (i[0][0] < folio_list.length) {
renderPage(new_page, pageMap, folio_list[i[0][0]][i[0][1]], 0, pH/2, cell_w, cell_h, UP_SIDE_DOWN)
renderPage(new_page, pageMap, folio_list[i[1][0]][i[1][1]], pW/2, pH/2, cell_w, cell_h, UP_SIDE_DOWN)
}
if (i[2][0] < folio_list.length) {
renderPage(new_page, pageMap, folio_list[i[2][0]][i[2][1]], 0, 0, cell_w, cell_h, RIGHT_SIDE_UP)
renderPage(new_page, pageMap, folio_list[i[3][0]][i[3][1]], pW/2, 0, cell_w, cell_h, RIGHT_SIDE_UP)
}
const targets = [ [cell_w, 0], [cell_w, pH/2], [cell_w, pH], [0, pH/2], [pW, pH/2] ];
targets.forEach( x => renderCrosshair(new_page, x[0], x[1]));
if (is_front)
this._renderFoldLine(new_page, 0, pH/2, pW, pH/2)
},
_handleSexto: function(new_page, pageMap, folio_list, sheet_index, is_front) {
const {pW, pH, renderPage, flip_short} = this._calcDimens(new_page)
const {pW, pH, renderPage, flip_short, renderCrosshair} = this._calcDimens(new_page)
const cell_w = pW/2;
const cell_h = pH/3;
const i = (is_front) ? [[0, 0], [0,3], [1,1], [1,2], [2, 0], [2, 3]]
: (flip_short) ? [[2, 1], [2,2], [1,0], [1,3], [0, 1], [0, 2]]
: [[0, 2], [0,1], [1,3], [1,0], [2, 2], [2, 1]]
const outerFlip = (is_front) ? UP_SIDE_DOWN : (flip_short) ? RIGHT_SIDE_UP : UP_SIDE_DOWN
const innerFlip = (is_front) ? RIGHT_SIDE_UP : (flip_short) ? UP_SIDE_DOWN : RIGHT_SIDE_UP
if (folio_list.length < 1)
return
renderPage(new_page, pageMap, folio_list[i[0][0]][i[0][1]], 0, 2 * pH/3, cell_w, cell_h, outerFlip)
renderPage(new_page, pageMap, folio_list[i[1][0]][i[1][1]], pW/2, 2 * pH/3, cell_w, cell_h, outerFlip)
if (folio_list.length < 2)
return
renderPage(new_page, pageMap, folio_list[i[2][0]][i[2][1]], 0, pH/3, cell_w, cell_h, innerFlip)
renderPage(new_page, pageMap, folio_list[i[3][0]][i[3][1]], pW/2, pH/3, cell_w, cell_h, innerFlip)
if (folio_list.length < 3)
return
renderPage(new_page, pageMap, folio_list[i[4][0]][i[4][1]], 0, 0, cell_w, cell_h, outerFlip)
renderPage(new_page, pageMap, folio_list[i[5][0]][i[5][1]], pW/2, 0, cell_w, cell_h, outerFlip)
if (i[0][0] < folio_list.length) {
renderPage(new_page, pageMap, folio_list[i[0][0]][i[0][1]], 0, 2 * pH/3, cell_w, cell_h, outerFlip)
renderPage(new_page, pageMap, folio_list[i[1][0]][i[1][1]], pW/2, 2 * pH/3, cell_w, cell_h, outerFlip)
}
if (i[2][0] < folio_list.length) {
renderPage(new_page, pageMap, folio_list[i[2][0]][i[2][1]], 0, pH/3, cell_w, cell_h, innerFlip)
renderPage(new_page, pageMap, folio_list[i[3][0]][i[3][1]], pW/2, pH/3, cell_w, cell_h, innerFlip)
}
if (i[4][0] < folio_list.length) {
renderPage(new_page, pageMap, folio_list[i[4][0]][i[4][1]], 0, 0, cell_w, cell_h, outerFlip)
renderPage(new_page, pageMap, folio_list[i[5][0]][i[5][1]], pW/2, 0, cell_w, cell_h, outerFlip)
}
const targets = [ [0, cell_h], [0, cell_h * 2], [cell_w, 0], [cell_w, cell_h], [cell_w, cell_h * 2], [cell_w, pH], [pW, cell_h], [pW, cell_h * 2]];
targets.forEach( x => renderCrosshair(new_page, x[0], x[1]));
if (is_front || (!is_front && flip_short))
this._renderFoldLine(new_page, 0, cell_h * 2, pW, cell_h * 2)
if (!is_front && !flip_short)
this._renderFoldLine(new_page, 0, cell_h, pW, cell_h)
},
_handleOctoFat: function(new_page, pageMap, folio_list, sheet_index, is_front) {
const renderPage = this._renderPage.bind(this)
Expand All @@ -329,7 +347,7 @@ export const imposerMagic = {
})
},
_handleOctoThin: function(new_page, pageMap, folio_list, sheet_index, is_front) {
const {pW, pH, renderPage, flip_short} = this._calcDimens(new_page)
const {pW, pH, renderPage, flip_short, renderCrosshair} = this._calcDimens(new_page)
const cell_w = pW/2;
const cell_h = pH/4;
// upper right, upper left, lower left, lower right
Expand All @@ -352,6 +370,19 @@ export const imposerMagic = {
renderPage(new_page, pageMap, folio_list[i[6][0]][i[6][1]], pW/2, pH/4, cell_w, cell_h, BOTTOM_TO_RIGHT)
renderPage(new_page, pageMap, folio_list[i[7][0]][i[7][1]], pW/2, 0, cell_w, cell_h, BOTTOM_TO_RIGHT)
}
if (is_front) {
this._renderFoldLine(new_page, pW/2, 0, pW/2, pH)
this._renderFoldLine(new_page, pW/2, pH/2, pW, pH/2)
}
const targets = [];
for(let j = 0; j <= pH; j += cell_h) {
targets.push([cell_w, j])
if (j != 0 && j != pH) {
targets.push([0, j])
targets.push([pW, j])
}
}
targets.forEach( x => renderCrosshair(new_page, x[0], x[1]));
},
// FRONT : folio [0] & [3] BACK : folio [1] & [2]
imposePdf: function(new_page, pageMap, folio_list, sheet_index, is_front) {
Expand Down
2 changes: 2 additions & 0 deletions js/pdf.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ export const builder = {
console.log(" > Sheet count ["+sheetCount+"] -> ",sheets)

sheets.forEach((s,i) => {
if (s.length == 0)
return;
if (side_coverage_mode == SIDE_COVERAGE_BOTH || side_coverage_mode == SIDE_COVERAGE_FRONT) {
const new_page = new_pdf.addPage();
imposerMagic.imposePdf(new_page, pageMap, s, i, true);
Expand Down

0 comments on commit 70a8fd4

Please sign in to comment.