mirror of
https://github.com/PR0M3TH3AN/Artstr-Studio.git
synced 2026-10-27 08:40:39 +00:00
book(E1): vendor pdf-lib + book PDF export skeleton
First slice of Phase E. The Pages overview now has an Export PDF… button that walks the physical-page sequence, renders each page at print DPI, and stamps them into a single PDF via pdf-lib. Library: - Vendored [email protected].1 as src/vendor/pdf-lib.min.js (~513 KB, MIT). Lazy-loaded through loadPdfLibOnce() so the cost is only paid when an author actually exports. Pipeline: - exportBookToPdf({ dpi, includeCover }) walks enumerateBookPhysicalPages(book), rendering each slot at the resolved DPI (default 200) onto a trim-sized canvas: * Designed pages → master underlay + page layers via drawLayerToCanvas, with token substitution applied to master text layers (book.spec.textStyles tokens resolve per page). * Reflow physical pages → master underlay (with text-frame outline stripped) + the pagination engine's block output drawn via fillText at the frame's coordinates. * Cover → wide spread canvas, all book-cover-* / book-spine layers drawn in place. - Each canvas converts to PNG via canvas.toBlob → Uint8Array, then pdf-lib's embedPng + addPage at trimW×trimH points (cover spread is its own landscape page at the end). UI: - Export PDF… button in the Pages overview toolbar with a status line that surfaces progress + warnings (failed image embeds, per-page render errors). - Filename = `<title-slug>.pdf`. Known v1 limitations (handled in later E phases): - Raster-only: every page is a PNG inside the PDF. Real PDF text for embeddable-allowlist fonts comes in E3. - No bleed-inclusive output / crop marks / page-range / two-file modes yet (E2). - Linked-design layers + premium-gated content not exercised. Co-Authored-By: Claude Opus 4.7 <[email protected]>
This commit is contained in:
1 parent
55f53aeb49
commit
f4243887cc
2 files changed
+293
-1
No files matched your search
+277
-1
@@ -4417,10 +4417,12 @@
|
||||
<button type="button" id="bookAddPageBtn" class="primary">+ Add page</button>
|
||||
<button type="button" id="bookAddTenBtn">+ Add 10 pages</button>
|
||||
<button type="button" id="bookAddChapterBtn">+ Add chapter</button>
|
||||
<button type="button" id="bookExportPdfBtn" title="Export this book as a PDF (interior pages + cover spread)">Export PDF…</button>
|
||||
<span id="bookExportPdfStatus" class="hint" style="margin-left:6px;font-size:.74rem"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="deckSlideGrid" id="bookPagesGrid"></div>
|
||||
<p class="hint" id="bookPagesHint" style="margin:8px 0 0">Click a designed-page tile to edit it on the canvas. Click a chapter tile to edit its markdown. Per-page Nostr publish (per-event sidecars + manifest) lands in Phase D1.</p>
|
||||
<p class="hint" id="bookPagesHint" style="margin:8px 0 0">Click a designed-page tile to edit it on the canvas. Click a chapter tile to edit its markdown. PDF export is raster-only in v1 (real-text mode for embeddable fonts lands in a follow-up slice).</p>
|
||||
</div>
|
||||
<div id="bookCoverView" style="display:none">
|
||||
<div class="bookCoverSummary" id="bookCoverSummary"></div>
|
||||
@@ -25047,6 +25049,279 @@
|
||||
// Slide / Custom Art / Pixel Art standalone: one flat rectangle of
|
||||
// layers on a background colour. Slides share the customart payload
|
||||
// shape under `state.customArt`.
|
||||
// ---- Book PDF export (Phase E1) -------------------------------------
|
||||
// pdf-lib lazy-load. Vendored as ~513 KB so we don't pay the
|
||||
// cost on every page-load; the export modal triggers this.
|
||||
let _pdfLibPromise = null;
|
||||
function loadPdfLibOnce() {
|
||||
if (window.PDFLib) return Promise.resolve(window.PDFLib);
|
||||
if (_pdfLibPromise) return _pdfLibPromise;
|
||||
_pdfLibPromise = loadScriptOnce('vendor/pdf-lib.min.js').then(() => {
|
||||
if (!window.PDFLib) throw new Error('pdf-lib loaded but PDFLib global is missing');
|
||||
return window.PDFLib;
|
||||
}).catch(err => {
|
||||
_pdfLibPromise = null;
|
||||
throw err;
|
||||
});
|
||||
return _pdfLibPromise;
|
||||
}
|
||||
// Render one designed page (master underlay + page layers) to a
|
||||
// print-DPI canvas. Token substitution is applied to master text
|
||||
// layers so `{page-number}` etc resolve correctly per page.
|
||||
async function renderBookDesignedPageToCanvas(entry, dpi, ctxToken) {
|
||||
const book = state.book || {};
|
||||
const spec = book.spec || {};
|
||||
const trimW = Number(spec.trimW) || 6;
|
||||
const trimH = Number(spec.trimH) || 9;
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = setupExportCanvas(canvas, trimW, trimH, dpi);
|
||||
const bg = entry.background || spec.background || '#ffffff';
|
||||
if (bg && bg.toLowerCase() !== '#ffffff' && bg.toLowerCase() !== '#fff') {
|
||||
ctx.fillStyle = bg;
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
// Page coords on the editor have x/y relative to the bleed-
|
||||
// inclusive artboard origin; for PDF export at trim-only size
|
||||
// we offset by -bleed so the page renders at (0,0).
|
||||
const bleed = Number(spec.bleed) || 0;
|
||||
const offX = -bleed * dpi;
|
||||
const offY = -bleed * dpi;
|
||||
// Master underlay first.
|
||||
const masterId = effectiveMasterIdForPage(entry);
|
||||
const masterTarget = masterId ? `book-master:${masterId}` : null;
|
||||
const masterLayers = masterTarget
|
||||
? (state.layers || [])
|
||||
.filter(l => l.target === masterTarget && !l.hidden
|
||||
&& !(l.type === 'shape' && l.shape?.kind === 'text-frame'))
|
||||
.slice().sort((a, b) => (a.z || 0) - (b.z || 0))
|
||||
: [];
|
||||
const subMaster = applyBookTokensToLayers(masterLayers, ctxToken);
|
||||
for (const l of subMaster) await drawLayerToCanvas(ctx, l, dpi, offX, offY);
|
||||
// Page layers on top.
|
||||
const pageTarget = `book-page:${entry.id}`;
|
||||
const pageLayers = (state.layers || [])
|
||||
.filter(l => l.target === pageTarget && !l.hidden)
|
||||
.slice().sort((a, b) => (a.z || 0) - (b.z || 0));
|
||||
const subPage = applyBookTokensToLayers(pageLayers, ctxToken);
|
||||
for (const l of subPage) await drawLayerToCanvas(ctx, l, dpi, offX, offY);
|
||||
return canvas;
|
||||
}
|
||||
// Render one physical page of a reflow segment: master underlay
|
||||
// (with the text-frame outline stripped) + paginated text blocks
|
||||
// drawn via fillText at the frame's coordinates.
|
||||
async function renderBookReflowPhysicalPageToCanvas(entry, paginated, indexInEntry, dpi, ctxToken) {
|
||||
const book = state.book || {};
|
||||
const spec = book.spec || {};
|
||||
const trimW = Number(spec.trimW) || 6;
|
||||
const trimH = Number(spec.trimH) || 9;
|
||||
const bleed = Number(spec.bleed) || 0;
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = setupExportCanvas(canvas, trimW, trimH, dpi);
|
||||
const bg = spec.background || '#ffffff';
|
||||
if (bg && bg.toLowerCase() !== '#ffffff' && bg.toLowerCase() !== '#fff') {
|
||||
ctx.fillStyle = bg;
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
// Master layers (no text-frame outline).
|
||||
const masterId = effectiveMasterIdForPage(entry);
|
||||
if (masterId) {
|
||||
const masterTarget = `book-master:${masterId}`;
|
||||
const masterLayers = (state.layers || [])
|
||||
.filter(l => l.target === masterTarget && !l.hidden
|
||||
&& !(l.type === 'shape' && l.shape?.kind === 'text-frame'))
|
||||
.slice().sort((a, b) => (a.z || 0) - (b.z || 0));
|
||||
const subMaster = applyBookTokensToLayers(masterLayers, ctxToken);
|
||||
const offX = -bleed * dpi;
|
||||
const offY = -bleed * dpi;
|
||||
for (const l of subMaster) await drawLayerToCanvas(ctx, l, dpi, offX, offY);
|
||||
}
|
||||
// Paint the paginated text blocks for this physical page.
|
||||
const page = paginated.pages[indexInEntry];
|
||||
const frame = paginated.frame;
|
||||
if (!page || !frame) return canvas;
|
||||
const padding = Number(frame.padding) || 0;
|
||||
const innerX = (frame.x + padding) - bleed; // trim-relative inches
|
||||
const innerY = (frame.y + padding) - bleed;
|
||||
for (const block of (page.blocks || [])) {
|
||||
const style = block.style || {};
|
||||
const fontSizePt = Number(style.fontSize) || 11;
|
||||
const fontPx = fontSizePt * (dpi / 72);
|
||||
const family = style.fontFamily || 'Georgia, serif';
|
||||
const weight = style.fontWeight || 400;
|
||||
const styleAttr = style.fontStyle || 'normal';
|
||||
ctx.font = `${styleAttr} ${weight} ${fontPx}px ${family}`;
|
||||
ctx.fillStyle = style.color || '#111';
|
||||
ctx.textBaseline = 'top';
|
||||
const align = style.alignment || 'left';
|
||||
ctx.textAlign = align === 'center' ? 'center' : align === 'right' ? 'right' : 'left';
|
||||
const blockYPx = (innerY * dpi) + (Number(block.y) || 0) * dpi;
|
||||
const marginLeftIn = Number(style.marginLeft) || 0;
|
||||
const marginRightIn = Number(style.marginRight) || 0;
|
||||
const xStartIn = innerX + marginLeftIn;
|
||||
const lineH = fontPx * (Number(style.lineHeight) || 1.5);
|
||||
for (let i = 0; i < (block.lines || []).length; i++) {
|
||||
let xPx;
|
||||
if (align === 'center') {
|
||||
const widthIn = (frame.w - 2 * padding) - marginLeftIn - marginRightIn;
|
||||
xPx = (xStartIn + widthIn / 2) * dpi;
|
||||
} else if (align === 'right') {
|
||||
const rightIn = innerX + (frame.w - 2 * padding) - marginRightIn;
|
||||
xPx = rightIn * dpi;
|
||||
} else {
|
||||
xPx = xStartIn * dpi;
|
||||
}
|
||||
ctx.fillText(block.lines[i], xPx, blockYPx + i * lineH);
|
||||
}
|
||||
}
|
||||
return canvas;
|
||||
}
|
||||
// Render the cover spread to one wide canvas. Layers carry their
|
||||
// own book-cover-front / book-cover-back / book-spine targets
|
||||
// already positioned in inch-space across the full spread.
|
||||
async function renderBookCoverToCanvas(dpi) {
|
||||
const spec = state.book?.spec || {};
|
||||
const trimW = Number(spec.trimW) || 6;
|
||||
const trimH = Number(spec.trimH) || 9;
|
||||
const bleed = Number(spec.bleed) || 0;
|
||||
const hasBack = !!spec.coverHasBack;
|
||||
const hasSpine = !!spec.coverHasSpine;
|
||||
const spineW = hasSpine ? bookSpineWidthInches() : 0;
|
||||
const spreadW = (hasBack ? trimW : 0) + spineW + trimW + bleed * 2;
|
||||
const spreadH = trimH + bleed * 2;
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = setupExportCanvas(canvas, spreadW, spreadH, dpi);
|
||||
const bg = spec.coverBackground || '#ffffff';
|
||||
if (bg && bg.toLowerCase() !== '#ffffff' && bg.toLowerCase() !== '#fff') {
|
||||
ctx.fillStyle = bg;
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
const coverLayers = (state.layers || [])
|
||||
.filter(l => /^book-cover-|^book-spine$/.test(String(l.target || '')) && !l.hidden)
|
||||
.slice().sort((a, b) => (a.z || 0) - (b.z || 0));
|
||||
for (const l of coverLayers) await drawLayerToCanvas(ctx, l, dpi);
|
||||
return canvas;
|
||||
}
|
||||
// Helper: canvas → PNG Uint8Array (pdf-lib's embedPng wants raw bytes).
|
||||
function _canvasToPngBytes(canvas) {
|
||||
return new Promise((resolve, reject) => {
|
||||
canvas.toBlob(async (blob) => {
|
||||
if (!blob) return reject(new Error('Canvas toBlob returned null'));
|
||||
try {
|
||||
const buf = await blob.arrayBuffer();
|
||||
resolve(new Uint8Array(buf));
|
||||
} catch (err) { reject(err); }
|
||||
}, 'image/png');
|
||||
});
|
||||
}
|
||||
// Phase E1 orchestrator. Walks the physical-page sequence, renders
|
||||
// each to canvas, embeds as PDF pages. Returns { blob, warnings }.
|
||||
async function exportBookToPdf(opts = {}) {
|
||||
const PDFLib = await loadPdfLibOnce();
|
||||
const book = state.book;
|
||||
if (!book) throw new Error('No book to export.');
|
||||
const dpi = Math.max(72, Math.min(450, Number(opts.dpi) || 200));
|
||||
const includeCover = opts.includeCover !== false;
|
||||
const seq = enumerateBookPhysicalPages(book);
|
||||
if (!seq.length && !(includeCover && book.cover)) {
|
||||
throw new Error('Nothing to export — add at least one page or chapter first.');
|
||||
}
|
||||
const pdfDoc = await PDFLib.PDFDocument.create();
|
||||
const warnings = [];
|
||||
_exportFailedImages.clear();
|
||||
// Per physical page.
|
||||
const reflowCache = new Map(); // entryId → paginateChapter result
|
||||
const spec = book.spec || {};
|
||||
const trimWpt = (Number(spec.trimW) || 6) * 72;
|
||||
const trimHpt = (Number(spec.trimH) || 9) * 72;
|
||||
for (const slot of seq) {
|
||||
const entry = book.pages.find(p => p.id === slot.entryId);
|
||||
if (!entry) continue;
|
||||
const ctxToken = bookTokenContext(book, slot.entryId, slot.indexInEntry);
|
||||
let canvas;
|
||||
try {
|
||||
if (slot.type === 'reflow') {
|
||||
let pag = reflowCache.get(slot.entryId);
|
||||
if (!pag) { pag = paginateChapter(entry, book); reflowCache.set(slot.entryId, pag); }
|
||||
canvas = await renderBookReflowPhysicalPageToCanvas(entry, pag, slot.indexInEntry, dpi, ctxToken);
|
||||
} else {
|
||||
canvas = await renderBookDesignedPageToCanvas(entry, dpi, ctxToken);
|
||||
}
|
||||
} catch (err) {
|
||||
warnings.push(`Page ${(slot.pageNumber != null) ? slot.pageNumber : '?'}: ${err.message || err}`);
|
||||
continue;
|
||||
}
|
||||
const png = await _canvasToPngBytes(canvas);
|
||||
const embedded = await pdfDoc.embedPng(png);
|
||||
const page = pdfDoc.addPage([trimWpt, trimHpt]);
|
||||
page.drawImage(embedded, { x: 0, y: 0, width: trimWpt, height: trimHpt });
|
||||
}
|
||||
// Cover spread on its own landscape page at the end.
|
||||
if (includeCover && book.cover) {
|
||||
try {
|
||||
const coverCanvas = await renderBookCoverToCanvas(dpi);
|
||||
const png = await _canvasToPngBytes(coverCanvas);
|
||||
const embedded = await pdfDoc.embedPng(png);
|
||||
const spec2 = book.spec || {};
|
||||
const trimW = Number(spec2.trimW) || 6;
|
||||
const trimH = Number(spec2.trimH) || 9;
|
||||
const bleed = Number(spec2.bleed) || 0;
|
||||
const hasBack = !!spec2.coverHasBack;
|
||||
const hasSpine = !!spec2.coverHasSpine;
|
||||
const spineW = hasSpine ? bookSpineWidthInches() : 0;
|
||||
const spreadW = (hasBack ? trimW : 0) + spineW + trimW + bleed * 2;
|
||||
const spreadH = trimH + bleed * 2;
|
||||
const page = pdfDoc.addPage([spreadW * 72, spreadH * 72]);
|
||||
page.drawImage(embedded, { x: 0, y: 0, width: spreadW * 72, height: spreadH * 72 });
|
||||
} catch (err) {
|
||||
warnings.push(`Cover: ${err.message || err}`);
|
||||
}
|
||||
}
|
||||
if (_exportFailedImages.size) {
|
||||
warnings.push(`${_exportFailedImages.size} image${_exportFailedImages.size === 1 ? '' : 's'} could not be embedded (CORS / missing).`);
|
||||
}
|
||||
const bytes = await pdfDoc.save();
|
||||
const blob = new Blob([bytes], { type: 'application/pdf' });
|
||||
return { blob, warnings };
|
||||
}
|
||||
async function downloadBookPdf() {
|
||||
const book = state.book;
|
||||
if (!book) return;
|
||||
const btn = document.getElementById('bookExportPdfBtn');
|
||||
const status = document.getElementById('bookExportPdfStatus');
|
||||
const setStatus = (text, kind) => {
|
||||
if (!status) return;
|
||||
status.textContent = text || '';
|
||||
status.style.color = kind === 'error' ? '#b91c1c'
|
||||
: kind === 'ok' ? '#15803d' : 'var(--muted)';
|
||||
};
|
||||
if (btn) btn.disabled = true;
|
||||
setStatus('Rendering PDF…');
|
||||
try {
|
||||
const { blob, warnings } = await exportBookToPdf();
|
||||
const a = document.createElement('a');
|
||||
const url = URL.createObjectURL(blob);
|
||||
const slug = (state.meta?.title || 'book')
|
||||
.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 64);
|
||||
a.href = url;
|
||||
a.download = `${slug || 'book'}.pdf`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
setTimeout(() => URL.revokeObjectURL(url), 4000);
|
||||
if (warnings.length) {
|
||||
setStatus(`Exported with ${warnings.length} warning${warnings.length === 1 ? '' : 's'}: ${warnings[0]}`, 'error');
|
||||
} else {
|
||||
setStatus(`Exported ${(blob.size / 1024).toFixed(0)} KB.`, 'ok');
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('PDF export failed', err);
|
||||
setStatus('Export failed: ' + (err?.message || 'unknown'), 'error');
|
||||
} finally {
|
||||
if (btn) btn.disabled = false;
|
||||
}
|
||||
}
|
||||
// ---- end Book PDF export --------------------------------------------
|
||||
|
||||
async function renderCustomArtToExportCanvas(dpi) {
|
||||
const ca = state.customArt || { width: 1920, height: 1080, background: '#ffffff' };
|
||||
const wIn = (Number(ca.width) || 1920) / 96;
|
||||
@@ -34461,6 +34736,7 @@
|
||||
on('bookViewTogglePages', 'click', () => setBookSubView('pages'));
|
||||
on('bookViewToggleCover', 'click', () => setBookSubView('cover'));
|
||||
on('bookCoverEditBtn', 'click', openBookCover);
|
||||
on('bookExportPdfBtn', 'click', downloadBookPdf);
|
||||
on('bookPageEditBack', 'click', () => {
|
||||
// Same back-button serves per-page, per-master, and cover modes.
|
||||
if (state.book?.editingMasterId) closeBookMaster();
|
||||
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t=t||self).PDFLib={})}(this,(function(t){"use strict";
|
||||
/*! *****************************************************************************
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
this file except in compliance with the License. You may obtain a copy of the
|
||||
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
MERCHANTABLITY OR NON-INFRINGEMENT.
|
||||
|
||||
See the Apache Version 2.0 License for specific language governing permissions
|
||||
and limitations under the License.
|
||||
***************************************************************************** */var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])})(t,n)};function n(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}var r=function(){return(r=Object.assign||function(t){for(var e,n=1,r=arguments.length;n<r;n++)for(var i in e=arguments[n])Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=e[i]);return t}).apply(this,arguments)};function i(t,e,n,r){return new(n||(n=Promise))((function(i,o){function a(t){try{l(r.next(t))}catch(t){o(t)}}function s(t){try{l(r.throw(t))}catch(t){o(t)}}function l(t){var e;t.done?i(t.value):(e=t.value,e instanceof n?e:new n((function(t){t(e)}))).then(a,s)}l((r=r.apply(t,e||[])).next())}))}function o(t,e){var n,r,i,o,a={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return o={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(o[Symbol.iterator]=function(){return this}),o;function s(o){return function(s){return function(o){if(n)throw new TypeError("Generator is already executing.");for(;a;)try{if(n=1,r&&(i=2&o[0]?r.return:o[0]?r.throw||((i=r.return)&&i.call(r),0):r.next)&&!(i=i.call(r,o[1])).done)return i;switch(r=0,i&&(o=[2&o[0],i.value]),o[0]){case 0:case 1:i=o;break;case 4:return a.label++,{value:o[1],done:!1};case 5:a.label++,r=o[1],o=[0];continue;case 7:o=a.ops.pop(),a.trys.pop();continue;default:if(!(i=a.trys,(i=i.length>0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]<i[3])){a.label=o[1];break}if(6===o[0]&&a.label<i[1]){a.label=i[1],i=o;break}if(i&&a.label<i[2]){a.label=i[2],a.ops.push(o);break}i[2]&&a.ops.pop(),a.trys.pop();continue}o=e.call(t,a)}catch(t){o=[6,t],r=0}finally{n=i=0}if(5&o[0])throw o[1];return{value:o[0]?o[1]:void 0,done:!0}}([o,s])}}}function a(){for(var t=0,e=0,n=arguments.length;e<n;e++)t+=arguments[e].length;var r=Array(t),i=0;for(e=0;e<n;e++)for(var o=arguments[e],a=0,s=o.length;a<s;a++,i++)r[i]=o[a];return r}for(var s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",l=new Uint8Array(256),h=0;h<s.length;h++)l[s.charCodeAt(h)]=h;var u,c=function(t){for(var e="",n=t.length,r=0;r<n;r+=3)e+=s[t[r]>>2],e+=s[(3&t[r])<<4|t[r+1]>>4],e+=s[(15&t[r+1])<<2|t[r+2]>>6],e+=s[63&t[r+2]];return n%3==2?e=e.substring(0,e.length-1)+"=":n%3==1&&(e=e.substring(0,e.length-2)+"=="),e},d=function(t){var e,n,r,i,o,a=.75*t.length,s=t.length,h=0;"="===t[t.length-1]&&(a--,"="===t[t.length-2]&&a--);var u=new Uint8Array(a);for(e=0;e<s;e+=4)n=l[t.charCodeAt(e)],r=l[t.charCodeAt(e+1)],i=l[t.charCodeAt(e+2)],o=l[t.charCodeAt(e+3)],u[h++]=n<<2|r>>4,u[h++]=(15&r)<<4|i>>2,u[h++]=(3&i)<<6|63&o;return u},f=/^(data)?:?([\w\/\+]+)?;?(charset=[\w-]+|base64)?.*,/i,p=function(t){var e=t.trim(),n=e.substring(0,100).match(f);if(!n)return d(e);var r=n[0],i=e.substring(r.length);return d(i)},g=function(t){return t.charCodeAt(0)},v=function(t){return t.codePointAt(0)},y=function(t,e){return x(t.toString(16),e,"0").toUpperCase()},m=function(t){return y(t,2)},b=function(t){return String.fromCharCode(t)},w=function(t){return b(parseInt(t,16))},x=function(t,e,n){for(var r="",i=0,o=e-t.length;i<o;i++)r+=n;return r+t},k=function(t,e,n){for(var r=t.length,i=0;i<r;i++)e[n++]=t.charCodeAt(i);return r},F=function(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")},S=function(t){return t.replace(/\t|\u0085|\u2028|\u2029/g," ").replace(/[\b\v]/g,"")},C=["\\n","\\f","\\r","\\u000B"],A=function(t){return/^[\n\f\r\u000B]$/.test(t)},T=function(t){return t.split(/[\n\f\r\u000B]/)},P=function(t){return t.replace(/[\n\f\r\u000B]/g," ")},z=function(t,e){var n,r=t.charCodeAt(e),i=e+1,o=1;return r>=55296&&r<=56319&&t.length>i&&(n=t.charCodeAt(i))>=56320&&n<=57343&&(o=2),[t.slice(e,e+o),o]},R=function(t){for(var e=[],n=0,r=t.length;n<r;){var i=z(t,n),o=i[0],a=i[1];e.push(o),n+=a}return e},O=function(t,e,n,r){for(var i=function(t){for(var e=C.join("|"),n=["$"],r=0,i=t.length;r<i;r++){var o=t[r];if(A(o))throw new TypeError("`wordBreak` must not include "+e);n.push(""===o?".":F(o))}var a=n.join("|");return new RegExp("("+e+")|((.*?)("+a+"))","gm")}(e),o=S(t).match(i),a="",s=0,l=[],h=function(){""!==a&&l.push(a),a="",s=0},u=0,c=o.length;u<c;u++){var d=o[u];if(A(d))h();else{var f=r(d);s+f>n&&h(),a+=d,s+=f}}return h(),l},D=/^D:(\d\d\d\d)(\d\d)?(\d\d)?(\d\d)?(\d\d)?(\d\d)?([+\-Z])?(\d\d)?'?(\d\d)?'?$/,B=function(t){var e=t.match(D);if(e){var n=e[1],r=e[2],i=void 0===r?"01":r,o=e[3],a=void 0===o?"01":o,s=e[4],l=void 0===s?"00":s,h=e[5],u=void 0===h?"00":h,c=e[6],d=void 0===c?"00":c,f=e[7],p=void 0===f?"Z":f,g=e[8],v=void 0===g?"00":g,y=e[9];return new Date(n+"-"+i+"-"+a+"T"+l+":"+u+":"+d+("Z"===p?"Z":""+p+v+":"+(void 0===y?"00":y)))}},N=function(t,e){for(var n,r,i=0;i<t.length;){var o=t.substring(i).match(e);if(!o)return{match:r,pos:i};r=o,i+=(null!==(n=o.index)&&void 0Line truncated
|
||||
//# sourceMappingURL=pdf-lib.min.js.map
|
||||
Reference in new issue
Block a user