Villainous Imposer Program
Launch February 4th 2025
- v0.0.6 - fixing opacity bug!! (thanks myro!)
- v0.0.5 - cropping of incoming PDF
- v0.0.4 - test print PDF generation
- v0.0.3 - reverse page order
- v0.0.2 - fix typo, fix octavo fat fold line, turned on rotation functionality
- v0.0.1 - disable rotation UI as it doesn't work yet
- v0.0.0 - launch!
- #4 #4 - origiami simulator and the
.fold
file format
There's a lot of features and a lot of work remaining--
- cut lines
- masking
- interweaving 2 PDF source (even/odds)
- export settings via .txt file
- persist/export/import imposer configurations
- export imposer debug information
- saving settings/URL params
- correctly re-rendering values when changing Display Units
- PDF placement preview
- debug info / error states / progress bars
- folding information / animations for impositions
- warn in PDF Placement if known exceeding of bounds (and by how much)
- dynamic button name change for Download from
get that file!
toget those files!
- figure out CORS stuff so it can be saved to someone's computer
- masking logic
- page numbers in the margins
- printer creep
- printer/PDF skew correction
- UI night mode colors
- more impositions
- improve Imposition options UI/UX to be more compact (in listing options section)
Processed in vip.processUploads
, offloads most the work to pdf.js
's processUploadBlocks
(which calls helper functions within that file). Tucks all results in window.book.upload_blocks
, each entry containing a _pagesList
array (-1
means blank!) and pdfDoc
(PDFLib.PDFDocument
)
Needs unified_source_modifier.attach()
to be called first to hook everything up (see state_modifiers.js
).
Call window.book.unified_source.processUpdate()
after base changes to re-calculate things. Things like:
window.book.unified_source.hasValidPdf()
: returns a booleanwindow.book.unified_source.maxWidth
/window.book.unified_source.maxHeight
: raw PDF height (post step 1)window.book.unified_source.isTurned()
: returns true if it's -90 or 90 degree rotation (post step 2)window.book.unified_source.pdf_w
/window.book.unified_source.pdf_h
: takes into account PDF margins and rotation. (post step 2)window.book.unified_source.pageCount
: calculated total pages across multiple PDFs and accounting for blankswindow.book.unified_source.getPdfPageForPageNumber(pageNum)
: given pageN
in the result PDF, looks up in thewindow.book.upload_blocks
to fetch the correspondingPDFLib.PDFPage
-- returns[upload_block_index, PDFPage]
This really highlights the mangling of terms. Height = Long Side = y
, Width = Short Side = x
window.book.physical.display_unit
: eithermetric
,imperial
, orpoints
window.book.physical.paper_size
: a 2 value list of the sheet's[width, height]
in pointswindow.book.physical.short_margin
: value to be mirrored on both sides of the paper (compressing total imposition)window.book.physical.long_margin
: value to be mirrored on both sides of the paper (compressing total imposition)
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, backwindow.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
Part of the imposer.js
code - tacked on AFTER the pages have been laid out and AFTER masking -- leverages functions such as _renderCrosshair
, _renderFoldLine
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)
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 callingdrawPage
on aPDFPage
, 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 the1
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
- don't forget, use
python3 -m http.server 8000
to launch local server